Dear stackoverflow members,
I have this string:
string data = "1Position1234Article4321Quantity2Position4323Article3323Quantity";
I want to search for the values where the "keyword" is Position. In this case I want to get back 1 and 2. Each value is "indexed" with its own "keyword". So the value 1 in this string has the Position seperator. The value 1234 has the Article seperator and the value 4321 has the Quantity seperator.
I need a way to search through the string and want to get all positions, articles and quantitys back. Without the keywords.
Output shout be:
string[] position = {"1", "2"};
string[] article = {"1234", "4323"};
string[] quantity = {"4321", "3323"};
Hopefully some can help me here.
Thanks!
This is q quick solution I've come up with in LinqPad:
void Main()
{
string data = "1Position1234Article4321Quantity2Position4323Article3323Quantity";
var Articles = Indices(data, "Article").Dump("Articles: ");
var Posistions = Indices(data, "Position").Dump("Positions :");
var Quantities = Indices(data, "Quantity").Dump("Quantities :");
}
// Define other methods and classes here
public List<int> Indices(string source, string keyword)
{
var results = new List<int>();
//source: http://stackoverflow.com/questions/3720012/regular-expression-to-split-string-and-number
var temp = Regex.Split(source, "(?<Alpha>[a-zA-Z]*)(?<Numeric>[0-9]*)").ToList().Where (r => !String.IsNullOrEmpty(r)).ToList();
//select the list with index only where key word matches
var indices = temp.Select ((v,i) => new {index = i, value = v})
.Where (t => t.value == keyword);
foreach (var element in indices)
{
int val;
//get previous list entry based on index and parse it
if(Int32.TryParse(temp[element.index -1], out val))
{
results.Add(val);
}
}
return results;
}
Output:
Here's a possible algorithm:
Run trough the list and take each number / keyword.
Put them in a dictionary with key "keyword", value a list with all "numbers".
Iterate the dictionary and print they key + its values.
Below snippet can use to get the output like what you expected.
string data = "1Position1234Article4321Quantity2Position4323Article3323Quantity";
StringBuilder sb = new StringBuilder();
StringBuilder sbWord = new StringBuilder();
bool isDigit = false;
bool isChar = false;
Dictionary<int, string> dic = new Dictionary<int, string>();
int index = 0;
for (int i = 0; i < data.Length; i++)
{
if (char.IsNumber(data[i]))
{
isDigit = true;
if (isChar)
{
dic.Add(index, sb.ToString() + "|" + sbWord.ToString());
index++;
isChar = false;
sb.Remove(0, sb.Length);
sbWord.Remove(0, sbWord.Length);
}
}
else
{
isDigit = false;
isChar = true;
sbWord.Append(data[i]);
}
if (isDigit)
sb.Append(data[i]);
if (i == data.Length - 1)
{
dic.Add(index, sb.ToString() + "|" + sbWord.ToString());
}
}
List<string> Position = new List<string>();
List<string> Article = new List<string>();
List<string> Quantity = new List<string>();
if (dic.Count > 0)
{
for (int i = 0; i < dic.Count; i++)
{
if (dic[i].Split('|')[1] == "Position")
Position.Add(dic[i].Split('|')[0]);
else if (dic[i].Split('|')[1] == "Article")
Article.Add(dic[i].Split('|')[0]);
else
Quantity.Add(dic[i].Split('|')[0]);
}
}
string[] Position_array = Position.ToArray();
string[] Article_array = Article.ToArray();
string[] Quantity_array = Quantity.ToArray();
Try this simple solution.
class StrSplit{
public static void main(String args[]){
int i;
String str = "1Position1234Article4321Quantity2Position4323Article3323Quantity";
String pattern= "(?<=Position)|(?<=Article)|(?<=Quantity)";
String[] parts = str.split(pattern);
List<String> Position = new ArrayList<String>();
List<String> Article = new ArrayList<String>();
List<String> Quantity = new ArrayList<String>();
for( i=0;i<parts.length;i++)
{
pattern="Position";
String[] subParts;
if(parts[i].contains(pattern))
{
subParts = parts[i].split(pattern);
Position.add(subParts[0]);
}
pattern="Article";
if(parts[i].contains(pattern))
{
subParts = parts[i].split(pattern);
Article.add(subParts[0]);
}
pattern="Quantity";
if(parts[i].contains(pattern))
{
subParts = parts[i].split(pattern);
Quantity.add(subParts[0]);
}
}
System.out.println("Position:");
for(i = 0; i < Position.size(); i++) {
System.out.println(Position.get(i));
}
System.out.println("Article:");
for(i = 0; i < Article.size(); i++) {
System.out.println(Article.get(i));
}
System.out.println("Quantity:");
for(i = 0; i < Quantity.size(); i++) {
System.out.println(Quantity.get(i));
}
}
}
Output:
Position:
1
2
Article:
1234
4323
Quantity:
4321
3323
Related
There is a collection of input strings and a collection of query strings. For each query string, determine how many times it occurs in the list of input strings. Return an array of the results.
Function Description
The function matchingStrings must return an array of integers representing the frequency of occurrence of each query string in strings.
matchingStrings has the following parameters:
string strings[n] - an array of strings to search
string queries[q] - an array of query strings
Returns
int[q]: an array of results for each query
Solution
List<string> strings = new List<string> { "4", "aba", "baba", "aba", "xzxb" };
List<string> queries = new List<string> { "3", "aba", "xzxb", "ab" };
List<int> outputList = Result.matchingStrings(strings, queries);
for (int i = 0; i < outputList.Count; i++)
{
Console.WriteLine(outputList[i]);
}
public class Result
{
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int inputCount = 0;
Int32.TryParse(strings[0], out inputCount);
string[] input = strings.GetRange(1, strings.Count - 1).ToArray();
var stringsMap = new Dictionary<string, int>();
for (int i = 0; i < inputCount; i++)
{
if (stringsMap.ContainsKey(input[i]))
{
stringsMap[input[i]]++;
}
else
{
stringsMap.Add(input[i], 1);
}
}
int queryCount = 0;
Int32.TryParse(queries[0], out queryCount);
string[] queryStrings = queries.GetRange(1, queries.Count - 1).ToArray();
int[] output = new int[queryCount];
for (int i = 0; i < queryCount; i++)
{
if (stringsMap.ContainsKey(queryStrings[i]))
{
output[i] = stringsMap[queryStrings[i]];
}
}
List<int> outputList = output.ToList();
return outputList;
}
}
The code works fine for the given sample input in VS code. However, when it is inserted into the HackerRank online IDE, it returns no output. I do not understand what the problem could be.
This is my 100% solution in C#:
List<int> res = new List<int>();
int count=0;
for(int i=0; i<queries.Count; i++) {
count=0;
foreach(string s in strings) {
if(queries[i] == s) {
count++;
}
}
res.Add(count);
}
return res;
}
this is my solution in python
def matchingStrings(strings, queries):
hash_map=dict()
results=[]
for str in strings:
if str in hash_map:
hash_map[str]+=1
else:
hash_map[str]=1
for q in queries:
if q in hash_map:
results.append(hash_map[q])
else:
results.append(0)
return results
public static List<int> matchingStrings(List<string> strings, List<string> queries)
{
int count = 0;
List<int> countOfOccurences = new List<int>();
foreach(var query in queries){
count = strings.Where(x => x == query).Count();
countOfOccurences.Add(count);
}
return countOfOccurences;
}
Given a list of lists I am looking to create all possible combinations.
Example:
I have a list which holds 3 lists
List 1: Apple, Banana, Pear
List 2: Bed, Chair
List 3: Ben, Bob, Carl, Phil
From this I would expect to end up with a List of combinations
Apple_Bed_Ben
Apple_Bed_Bob
Apple_Bed_Carl
Apple_Bed_Phil
Apple_Chair_Ben
Apple_Chair_Bob
Apple_Chair_Carl
Apple_Chair_Phil
Banana_Bed_Ben
Banana_Bed_Bob
...
I don't know if I am missing something but I have been going in circles for hours now.
If I knew there would only ever be three lists I know I could just use nested for loops going through building the combination string but here there could be any number of lists.
Can anyone point me in the right direction to get this done?
This is what i currently have:
public class ChildrenNames
{
public string parentName;
public int numberOfNames;
public List<string> childrenNames = new List<string>();
}
public class Combination
{
public bool selected = true;
public string name;
}
List<Combination> GetAllCombinations()
{
List<Combination> allCombinations = new List<Combination>();
List<ChildrenNames> listOfChildren = new List<ChildrenNames>();
//Create list of children names for each parent object
for (int p = 0; p < parentObjects.Count; p++)
{
ChildrenNames cn = new ChildrenNames();
for (int c = 0; c < parentObjects[p].transform.childCount; c++)
cn.childrenNames.Add(parentObjects[p].transform.GetChild(c).name);
cn.parentName = parentObjects[p].name;
cn.numberOfNames = cn.childrenNames.Count;
listOfChildren.Add(cn);
}
for (int l = 0; l < listOfChildren.Count; l++)
{
for (int c = 0; c < listOfChildren[l].numberOfNames; c++)
{
if (l == 0)
{
for (int p = 0; p < listOfChildren.Count; p ++)
{
Combination combination = new Combination();
combination.name = listOfChildren[l].childrenNames[c];
allCombinations.Add(combination);
}
}
else
{
for (int i = 0; i < allCombinations.Count; i++)
allCombinations[i].name += "_" + listOfChildren[l].childrenNames[c];
}
}
}
return allCombinations;
}
This creates the correct number of combinations but for example throws out
Apple_Bed_Chair_Ben_Bob_Carl_Phil
I understand why this is happening but not how I can change this to get the expected result.
You need to keep track of the column for each of the lists in order for it to work properly.
public List<string> ZipStringLists(params List<string>[] lists)
{
var columnNo = new int[lists.Length];
var resultingList = new List<string>();
var stringBuilder = new StringBuilder();
while (columnNo[0] < lists[0].Count)
{
// Combine the items into one: Apple + Banana + Pear = AppleBananaPear
for (int i = 0; i < lists.Length; i++)
{
var listElement = lists[i];
// columnNo[i] contains which column to write out for the individual list
stringBuilder.Append(listElement[columnNo[i]]);
}
// Write out the result and add it to a result list for later retrieval
var result = stringBuilder.ToString();
resultingList.Add(result);
Console.WriteLine(result);
stringBuilder.Clear();
// We increment columnNo from the right to the left
// The next item after AppleBedBen is AppleBedBob
// Overflow to the next column happens when a column reaches its maximum value
for (int i = lists.Length - 1; i >= 0; i--)
{
if (++columnNo[i] == lists[i].Count
&& i != 0 /* The last column overflows when the computation finishes */)
{
// Begin with 0 again on overflow and continue to add to the next column
columnNo[i] = 0;
}
else
{
// No overflow -> stop
break;
}
}
}
return resultingList;
}
Usage:
List<string> list1 = new List<string> { "Apple", "Banana", "Pear" };
List<string> list2 = new List<string> { "Bed", "Chair" };
List<string> list3 = new List<string> { "Ben", "Bob", "Carl", "Phil" };
ZipStringLists(list1, list2, list3);
You could use a fairly generic solution that accepts any number of lists to incrementally build up the combinations. It's short, though not necessarily as optimal as other solutions as it builds intermediate lists:
public List<string> FindCombinations(params List<string>[] lists)
{
List<string> combinations = lists[0];
for (int i = 1; i < lists.Length; i++)
{
List<string> newCombinations = new List<string>(combinations.Count * lists[i].Count);
combinations.ForEach(s1 => lists[i].ForEach(s2 => newCombinations.Add($"{s1}_{s2}")));
combinations = newCombinations;
}
return combinations;
}
Usage:
List<string> combinations = FindCombinations(list1, list2, list3, list4, list5...)
I have a problem to solve where given a string source and a collection of search criteria criteria, the algorithm has to return the shortest possible substring of source that contains all items of criteria.
=================================
UPDATE
The same search criteria might be in the source string multiple
times. In that case, it is required to return the sub-string
containing the particular instance of the search criteria such that
it is the shortest among all possible sub-strings.
The search items can contain spaces in them such as hello world
The order in which the search criteria are found does not matter as long as they are all in the resultant sub-string
==================================
String source = "aaa wwwww fgffsd ththththt sss sgsgsgsghs bfbfb hhh sdfg kkk dhdhtrherhrhrthrthrt ddfhdetehehe kkk wdwd aaa vcvc hhh zxzx sss nbnbn";
List<String> criteria = new List<string> { "kkk", "aaa", "sss", "hhh" };
The input above should return the following substring: kkk wdwd aaa vcvc hhh zxzx sss
Unfortunately, I spent a lot of time trying to write such an algorithm but I couldn't get it just right. Below is the code I have got so far:
public struct Extraction
{
public int Start { get; set; }
public int End { get; set; }
public int Length
{
get
{
var length = this.End - this.Start;
return length;
}
}
public Extraction(int start, int end)
{
this.Start = start;
this.End = end;
}
}
public class TextExtractor
{
private String _source;
private Dictionary<String, List<Int32>> _criteriaIndexes;
private Dictionary<String, int> _entryIndex;
public TextExtractor(String source, List<String> searchCriteria)
{
this._source = source;
this._criteriaIndexes = this.ExtractIndexes(source, searchCriteria);
this._entryIndex = _criteriaIndexes.ToDictionary(x => x.Key, v => 0);
}
public String Extract()
{
List<Extraction> possibleExtractions = new List<Extraction>();
int index = 0;
int min = int.MaxValue;
int max = 0;
bool shouldStop = false;
while (index < _criteriaIndexes.Count && !shouldStop)
{
Boolean compareWithAll = index == _criteriaIndexes.Count - 1;
if (!compareWithAll)
{
var current = _criteriaIndexes.ElementAt(index);
this.CalculateMinMax(current, ref min, ref max);
index++;
}
else
{
var entry = _criteriaIndexes.Last();
while (_entryIndex[entry.Key] < entry.Value.Count)
{
int a = min;
int b = max;
this.CalculateMinMax(entry, ref a, ref b);
_entryIndex[entry.Key]++;
Extraction ext = new Extraction(a, b);
possibleExtractions.Add(ext);
}
int k = index - 1;
while (k >= 0)
{
var prev = _criteriaIndexes.ElementAt(k);
if (prev.Value.Count - 1 > _entryIndex[prev.Key])
{
_entryIndex[prev.Key]++;
break;
}
else
{
k--;
}
}
shouldStop = _criteriaIndexes.All(x => x.Value.Count - 1 <= _entryIndex[x.Key]);
_entryIndex[entry.Key] = 0;
index = 0;
min = int.MaxValue;
max = 0;
}
}
Extraction shortest = possibleExtractions.First(x => x.Length.Equals(possibleExtractions.Min(p => p.Length)));
String result = _source.Substring(shortest.Start, shortest.Length);
return result;
}
private Dictionary<String, List<Int32>> ExtractIndexes(String source, List<String> searchCriteria)
{
Dictionary<String, List<Int32>> result = new Dictionary<string, List<int>>();
foreach (var criteria in searchCriteria)
{
Int32 i = 0;
Int32 startingIndex = 0;
var indexes = new List<int>();
while (i > -1)
{
i = source.IndexOf(criteria, startingIndex);
if (i > -1)
{
startingIndex = i + 1;
indexes.Add(i);
}
}
if (indexes.Any())
{
result.Add(criteria, indexes);
}
}
return result;
}
private void CalculateMinMax(KeyValuePair<String, List<int>> current, ref int min, ref int max)
{
int j = current.Value[_entryIndex[current.Key]];
if (j < min)
{
min = j;
}
int indexPlusWordLength = j + current.Key.Length;
if (indexPlusWordLength > max)
{
max = indexPlusWordLength;
}
}
}
I would appreciate it if someone could point out where did I go wrong in my algorithm. Moreover, I kinda feel this is a very naive implementation. Maybe there is a better approach to solve this problem than trying to try out combinations of indexes?
Thanks!
This is a much simpler algorithm that will give you the shortest substring.
void Main()
{
String source = "aaa wwwww fgffsd ththththt sss ww sgsgsgsghs bfbfb hhh sdfg kkk " +
"dhdhtrherhrhrthrthrt ddfhdetehehe kkk wdwd aaa vcvc hhh zxzx sss ww nbnbn";
List<String> criteria = new List<string> { "kkk", "aaa", "sss ww", "hhh" };
var result = GetAllSubstringContainingCriteria(source, criteria)
.OrderBy(sub => sub.Length).FirstOrDefault();
// result is "kkk wdwd aaa vcvc hhh zxzx sss ww"
}
private IEnumerable<string> GetAllSubstringContainingCriteria(
string source, List<string> criteria)
{
for (int i = 0; i < source.Length; i++)
{
var subString = source.Substring(i);
if (criteria.Any(crit => subString.StartsWith(crit)))
{
var lastWordIndex =
GetLastCharacterIndexFromLastCriteriaInSubstring(subString, criteria);
if (lastWordIndex >= 0)
yield return string.Join(" ", subString.Substring(0, lastWordIndex));
}
else
continue;
}
}
private int GetLastCharacterIndexFromLastCriteriaInSubstring(
string subString, List<string> criteria)
{
var results = criteria.Select(crit => new {
index = subString.IndexOf(crit),
criteria = crit});
return results.All(result => result.index >= 0)
? results.Select(result => result.index + result.criteria.Length).Max()
: -1;
}
Let the Java built-in classes do the work. How about converting your criteria to a regular expression Pattern. If the criteria are X or Y or Z . . ., convert this into a regular expression of the form "(X)|(Y)|(Z)|...", compile it, and execute it against the source string.
This, of course, returns the leftmost match. You could code a very straightforward loop that iterates across all occurrences, caches them, and chooses the shortest--or the leftmost shortest--or, if two or more are equally short, then all of those.
My function is supposed to split a string by "&" ";" and "," and return a triple jagged array and vice versa. (From data like: 1,2,3;4,5,6&1,2,3;4,5,6)
I've been struggling hard to make it work, now for some reason I'm getting a system.argumentnullexception on
Array.Copy(playerOneEnts, allEnts[0], playerOneEnts.Length);
Array.Copy(playerTwoEnts, allEnts[1], playerTwoEnts.Length);
Full code:
public string convertToString(string[][][] allEnts)
{
string Player = string.Empty;
string[][] playerOneEnts = new string[maxEnts][];
string[][] playerTwoEnts = new string[maxEnts][];
Array.Copy(allEnts[0], playerOneEnts, allEnts[0].Length);
Array.Copy(allEnts[1], playerTwoEnts, allEnts[1].Length);
for (int j = 0; j < playerOneEnts.Length; j++)
{
for (int i = 0; i < playerOneEnts[j].Length; i++)
{
Player += playerOneEnts[j][i] + ",";
}
Player = Player.TrimEnd(',');
Player += ";";
}
Player = Player.TrimEnd(';');
Player += "&";
for (int j = 0; j < playerTwoEnts.Length; j++)
{
for (int i = 0; i < playerTwoEnts[j].Length; i++)
{
Player += playerTwoEnts[j][i] + ",";
}
Player = Player.TrimEnd(',');
Player += ";";
}
Player = Player.TrimEnd(';');
return Player;
}
public string[][][] convertToArray(string ents)
{
string[] p = new string[2];
string[][] playerOneEnts = new string[maxEnts][];
string[][] playerTwoEnts = new string[maxEnts][];
string[][][] allEnts = new string[2][][];
p = ents.Split('&');
try
{
playerOneEnts = p[0].Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Select(chunk => chunk.Split(',')).ToArray();
playerTwoEnts = p[1].Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Select(chunk => chunk.Split(',')).ToArray();
MessageBox.Show(playerOneEnts.Length.ToString());
Array.Copy(playerOneEnts, allEnts[0], playerOneEnts.Length);
Array.Copy(playerTwoEnts, allEnts[1], playerTwoEnts.Length);
}
catch
{
MessageBox.Show("unable to convert string", "Fatal Error");
}
return allEnts;
}
The code looks like a disaster to me, if anyone knows a nicer way to convert this to a string I'd be happy for any ideas. Getting rid of my Error would help me enough already.
Thanks!
Here is example using Linq (requires .Net 4.0):
var source = "1,2,3;4,5,6&1,2,3;4,5,6";
string[][][] decoded = source.Split('&').Select(x => x.Split(';').Select(y => y.Split(',').ToArray()).ToArray()).ToArray();
string reencoded = String.Join("&", decoded.Select(x => String.Join(";", x.Select(y => String.Join(",", y)))));
Alternatively IEnumarable generics can be used to avoid conversion to arrays.
Warning: This code doesn't validates input e.g. array lengths.
Edit: Re-encoder for .NET 3.5:
var reencoded = String.Join("&", decoded.Select(x => String.Join(";", x.Select(y => String.Join(",", y)).ToArray())).ToArray());
You can do it using nested for-loops like this:
string p = "1,2,3;4,5,6&1,5,3;4,5,9";
List<List<List<string>>> result = new List<List<List<string>>>();
foreach (var a in p.Split('&'))
{
List<List<string>> level2 = new List<List<string>>();
foreach (var b in a.Split(';'))
{
level2.Add(new List<string>(b.Split(',')));
}
result.Add(level2);
}
var x = result[0][1][2]; // This will result in '6'.
The encoding is similar:
string encoded;
List<string> dec1 = new List<string>();
foreach (var a in result)
{
string e = "";
List<string> z = new List<string>();
foreach (var b in a)
{
z.Add(String.Join(",", b));
}
e = String.Join(";", z);
dec1.Add(e);
}
encoded = String.Join("&", dec1);
I need to implement a module which will convert a List which with splitted string values to a possible value sets.
For Example
consider the list contains following values
1
1,2
3
4
5
The module should convert the above list to list of possible value sets
1,2,3,4,5
1,1,3,4,5
thanks in advance
This will do it, although it will return your example in the opposite order:
static IEnumerable<string> Permutations(
IEnumerable<string> input,
char separator)
{
var sepAsString = separator.ToString();
var enumerators = input
.Select(s => s.Split(separator).GetEnumerator())
.ToArray();
if (!enumerators.All(e => e.MoveNext())) yield break;
while (true)
{
yield return String.Join(sepAsString, enumerators.Select(e => e.Current));
if (enumerators.Reverse().All(e => {
bool finished = !e.MoveNext();
if (finished)
{
e.Reset();
e.MoveNext();
}
return finished;
}))
yield break;
}
}
Usage:
var list = new[] { "1", "1,2", "3", "4", "5" }.ToList();
var perms = Permutations(list, ',').ToList();
Rawling's answer is pretty solid, but i don't find it easy to read and understand. Here's another way, using less Linq.
private List<string> Process(IEnumerable<string> input)
{
List<string> data = new List<string>();
int preExpandCount = 0, offset = 0;
foreach (string inputItem in input)
{
List<string> splitItems = inputItem.Split(',').ToList();
if (data.Count > 0)
preExpandCount = ExpandList(data, splitItems.Count - 1);
offset = 0;
foreach (string splitItem in splitItems)
{
if (preExpandCount == 0)
data.Add(splitItem);
else
{
for (int i = 0; i < preExpandCount; i++)
data[i + offset] = String.Format("{0},{1}", data[i + offset], splitItem);
offset += preExpandCount;
}
}
}
return data.OrderBy(e => e).ToList();
}
private int ExpandList(List<string> existing, int count)
{
int existingCount = existing.Count;
for (int i = 0; i < count; i++)
existing.AddRange(existing.Take(existingCount).ToList());
return existingCount;
}