String Split: Key not found exception - c#

I have a string message that is separated by ':Item:' I want to put the items next to ':Item:' in a dictionary using a unique key
string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 0; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(1, 3), values[i]);
}
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
But this is giving me a key not found exception since values[0] does not have the ID i used as a key.
How can I skip the first element in the collection? or is there another efficient way?
EDIT:
What I want to put in the dictionary is :
key = "AA", value = "aaaaa"
key = "ID1", value = "ID1222222"
key = "ID3" valeu ="ID3444444"
key = "ID4" value "ID4555555"
thanks

You can use LINQ to get your expected output:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Substring(0, 3), x => x);
Results in LINQPad:
Note: Substring might throw exception if you have a key that contains less than three characters,in order to fix that you can do the following:
var dictionary = input.Split(':')
.Where(x => !x.Contains("Item"))
.ToDictionary(x => x.Length >=3 ? x.Substring(0, 3) : x, x => x);

string input = "aaaaa:Item:ID1222222:Item:ID3444444:Item:ID4555555";
var response = new Dictionary<string, string>();
string[] values = input.Split(':');
for (int i = 1; i < values.Length; i++)
{
if (!values[i].Contains("Item"))
{
// use the id as a unique key
response.Add(values[i].Substring(0, 3), values[i]);
}
}
for (int i = 0; i < response.Count; i++)
{
if (response.ContainsKey("ID1"))
{
Console.WriteLine(response["ID1"]);
Console.ReadLine();
}
}

Related

Proper way to assign KeyValuePair from two arrays

My array:
string[] name = "a,b,c,d".Split(',');//key
string[] path = "w,x,y,z".Split(',');//value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
I try to assign a value like this.
foreach (string s in name)
{
foreach (string sp in path)
{
list.Add(new KeyValuePair<string, string>(s, sp));
}
}
But my logic is fail. What is a proper way to assign a KeyValue pair from two arrays?
Expected outcome.
a-w
b-x
c-y
d-z
Try using:
string[] names = "a,b,c,d".Split(','); //key
string[] paths = "w,x,y,z".Split(','); //value
var namesAndPaths = names.Zip(paths, (name, path) => new KeyValuePair<string,string>(name, path));
You must use the same loop for both arrays (or use the LINQ solutions proposed in other answers):
string[] name = "a,b,c,d".Split(','); // Key
string[] path = "w,x,y,z".Split(','); // Value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length, i++)
{
if (i == path.Length) // In case both arrays are not the same length
{
break;
}
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
If you are sure that both arrays are equal length, you can do:
for (var i = 0; i < name.Length; ++i) {
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
Assuming both arrays will be of same length you can do this -
for(int i=0; i<name.Length; i++)
{
list.Add(new KeyValuePair<string, string>(name[i], path[i]));
}
string[] name = "a,b,c,d".Split(','); //key
string[] path = "w,x,y,z".Split(','); //value
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
for (int i = 0; i < name.Length; i++)
{
for (int j = 0; j < path.Length; j++)
{
if (i == j)
{
list.Add(new KeyValuePair<string, string>(name[i], path[j]));
}
}
}
You could do this using LINQ:
var mergedKeyValues = name.Select((n,i) => new KeyValuePair<string,string>(n,path[i]))
.ToList();
Output
[a, w]
,
[b, x]
,
[c, y]
,
[d, z]
Check out this demo.
Use a LINQ one-liner:
var d = name.Select((n, idx) => new { Name = n, Index = idx })
.ToDictionary(k => k.Name, v => path[v.Index]);
The key here is to use the index from the Select method to determine the index to use in the other array.

Can I store LINQ query result in an array?

This is the code using LINQ, it stores the values into list
string StringRegex = "\"(?:[^\"\\\\]|\\\\.)*\"";
Dictionary<string, string> dictionaryofString = new Dictionary<string, string>()
{
{"String", StringRegex}
};
var matches = dictionaryofString.SelectMany(a => Regex.Matches(input,a.Value)
.Cast<Match>()
.Select(b =>
new
{
Index = b.Index,
Value = b.Value,
Token = a.Key
}))
.OrderBy(a => a.Index).ToList();
for (int i = 0; i < matches.Count; i++)
{
if (i + 1 < matches.Count)
{
int firstEndPos = (matches[i].Index + matches[i].Value.Length);
if (firstEndPos > matches[(i + 1)].Index)
{
matches.RemoveAt(i + 1);
i--;
}
}
}
foreach (var match in matches)
{
Console.WriteLine(match);
}
Can it not be stored into Array? Where I can display only item I want. Just like here the output is {Index=, Value=, Token=}
Meanwhile I want the output that be of just "Value" "Token" index not needed.
You can use ToArray instead. But List gives you the desired array functionality already, you can access an item by its index.
var exampleQuery = select c from componentsDemo;
var list = exampleQuery.ToList();
var secondElement = list[1]; // <- demo only, there could be an exception thrown, if there's less than two elements in the list
EDIT: as I can see from your comments, you need this:
foreach (var match in matches)
{
Console.WriteLine(match.Value + ", " + match.Token);
}

How can we map a string with case sensitive?

I have my code like,
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',');
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
string[] fieldArrayList = fields.Split(',');
List<int> mappedList = new List<int>();
for (int i = 0; i< fieldArrayList.Count(); i++)
{
for (int j = 0; j < fieldArrayRecord.Count(); j++)
{
if (fieldArrayList[i] == fieldArrayRecord[j])
{
mappedList.Add(j);
}
}
}
How can i map, the "front Images" with "FrontImages".
As iam the beginner i dont know how to solve this.Kindly tell me how to achieve this.
For such a fuzzy match, you first need to identify the valid identifiers to ignore (in this case a space).
You could do something like this: You strip out all those identifiers. Then compare case and culture insensitive.
string normalizedHeaderString = "FrontImages";
string normalizedInputString = "front images";
foreach (string c in new[] { " " }) /* the strings to strip out */
{
normalizedHeaderString = normalizedHeaderString.Replace(c, null);
normalizedInputString = normalizedInputString.Replace(c, null);
}
if (string.Equals( normalizedHeaderString
, normalizedInputString
, StringComparison.OrdinalIgnoreCase
)
)
{ /* do your logic, like saving the index, etc */ }
This is a little hacky, but you get the idea. You'd better use a custom implementation of a StringComparer that just ignores the characters to strip out.
As I understand from your question, your problems are spaces and case sensitivity
so you can use
fieldArrayList[i].Replace(" ","").ToLower() ==
fieldArrayRecord[j].Replace(" ","").ToLower()
class Program
{
static void Main(string[] args)
{
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',');
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
string[] fieldArrayList = fields.Split(',');
List<int> mappedList = new List<int>();
for (int i = 0; i < fieldArrayRecord.Length; i++)
{
if (fieldArrayList.Any(s => string.Equals( fieldArrayRecord[i].Replace(" ", string.Empty), s, StringComparison.OrdinalIgnoreCase)))
{
mappedList.Add(i);
}
}
foreach (int index in mappedList)
{
Console.WriteLine(index);
}
}
}
Output:
0
1
3
4
Or using a dictionary:
class Program
{
static void Main(string[] args)
{
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
var dataFields = firstLineOfRecord.Split(',').Select((x, index) => new { FieldName = x.Replace(" ", string.Empty), Index = index });
var tableFields = fields.Split(',').Select((x, index) => new { FieldName = x, Index = index });
Dictionary<int, int> mapping = (from dataField in dataFields
let tableField = tableFields.SingleOrDefault(x => string.Equals(dataField.FieldName, x.FieldName, StringComparison.OrdinalIgnoreCase))
where tableField != null
select new { DF = dataField.Index, TF = tableField.Index })
.ToDictionary(c => c.DF, c => c.TF);
// Test:
string[] dataFieldsArray = firstLineOfRecord.Split(',');
string[] tableFieldsArray = fields.Split(',');
foreach (KeyValuePair<int,int> pair in mapping)
{
Console.WriteLine(
"TableField '{0}' Index {1} has to be mapped to DataField '{2}' Index {3}",
tableFieldsArray[pair.Value], pair.Value, dataFieldsArray[pair.Key],pair.Key);
}
}
}
Output:
TableField 'FrontImages' Index 0 has to be mapped to DataField 'front images' Index 0
TableField 'CurrencyCode' Index 3 has to be mapped to DataField 'Currency Code' Index 1
TableField 'BackImages' Index 1 has to be mapped to DataField 'BackImages' Index 3
TableField 'Domination' Index 2 has to be mapped to DataField 'Domination' Index 4
Here's a way to do it with a LINQ query:
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',')
.Select(x => x.Replace(" ", string.Empty))
.ToArray();
// Test it, prints True.
fieldArrayRecord.Contains("FrontImages", StringComparer.OrdinalIgnoreCase)
Note this will replace any white space between those letters and will alter the given fieldArrayRecord.

How to get the indexes and reoccurrences of a specific character?

IF in a string there is a character or characters that occurs again and again. Like in the following string:
1+1+1-2+2/2*4-2*3/23
Now in the string above the + occurs 3 times at the indexes of 1,3,7 and - occurs 2 times at the indexes of 5,13 and so others, and then storing them in 2 dimensional array So now the issue is that how to do this.
The following function will return all matched indices for a given search string:
List<int> GetAllIndices(string input, string search)
{
List<int> result = new List<int>();
int index = input.IndexOf(search);
while(index != -1)
{
result.Add(index);
index++;//increment to avoid matching the same index again
if(index >= input.Length)//check if index is greater than string (causes exception)
break;
index = input.IndexOf(search, index);
}
return result;
}
It should also handle overlapping matches, for example: searching "iii" for occurrences of "ii" will return [0,1]
If you want to use this function to create a list of symbols and their indices then I would recommend the following approach:
string input = "1+1+1-2+2/2*4-2*3/23";
//create a dictionary to store the results
Dictionary<string, List<int>> results = new Dictionary<string, List<int>>();
//add results for + symbol
results.Add("+", GetAllIndices(input, "+"));
//add results for - symbol
results.Add("-", GetAllIndices(input, "-"));
//you can then access all indices for a given symbol like so
foreach(int index in results["+"])
{
//do something with index
}
You could even go a step further and wrap that in a function that searches for multiple symbols:
Dictionary<string, List<int>> GetSymbolMatches(string input, params string[] symbols)
{
Dictionary<string, List<int>> results = new Dictionary<string, List<int>>();
foreach(string symbol in symbols)
{
results.Add(symbol, GetAllIndices(input, symbol));
}
return results;
}
Which you can then use like so:
string input = "1+1+1-2+2/2*4-2*3/23";
Dictionary<string, List<int>> results = GetSymbolMatches(input, "+", "-", "*", "/");
foreach(int index in results["+"])
{
//do something with index
}
With Linq:
var allIndices = yourString.Select((c, i) => new { c, i, })
.Where(a => a.c == '+').Select(a => a.i);
To get a dictionary with all characters in the string, for example:
var allCharsAllIndices = yourString.Select((c, i) => new { c, i, })
.GroupBy(a => a.c)
.ToDictionary(g => g.Key, g => g.Select(a => a.i).ToArray());
you can try this with changing 'value'
var duplicates = param1.ToCharArray().Select((item, index) => new { item, index })
.Where(x =>x.item==VALUE).GroupBy(g=>g.index)
.Select(g => new { Key = g.Key })
.ToList();
string msg = "1+1+1-2+2/2*4-2*3/23";
Dictionary<char, List<int>> list = new Dictionary<char, List<int>>();
for (int i = 0; i < msg.Length; i++)
{
if (!list.ContainsKey(msg[i]))
{
list.Add(msg[i], new List<int>());
list[msg[i]].Add(i);
}
else
list[msg[i]].Add(i);
}
Simple = best. Without memory allocation.
public static IEnumerable<int> GetIndexOfEvery(string haystack, string needle)
{
int index;
int pos = 0;
string s = haystack;
while((index = s.IndexOf(needle)) != -1)
{
yield return index + pos;
pos = pos + index + 1;
s = haystack.Substring(pos);
}
}

Grouping list elements to dictionary

I have a list that contains 8 elements:
ConfigFile.ControllerList
this list is type of:
List<Controller>
How can i add Controllers from ControllerList to 3 dictionary keys. Dictionary is like:
Dictionary<int, List<Controller>> ControllerDictionary = new Dictionary<int, List<Controller>>();
I want to add first 3 controllers to dictionary key 0, then want to add next 3 controllers to dictionary key 1 and lastly want to add last 2 controllers to dictionary key 2. How can i do that?
You can use / to split the list into sub-list:
var ControllerDictionary = ControllerList
.Select((c, i) => new { Controller = c, Index = i })
.GroupBy(x => x.Index / maxGroupSize)
.Select((g, i) => new { GroupIndex = i, Group = g })
.ToDictionary(x => x.GroupIndex, x => x.Group.Select(xx => xx.Controller).ToList());
The idea is to first group the elements by indexes, then divide them by an int maxGroupSize(in your case 3). Then convert each group to a list.
Not sure if there's a more elegant solution, but something like this should work:
var dict = new Dictionary<int, List<Controller>>();
int x = 0;
while (x < controllerList.Count)
{
var newList = new List<Controller> { controllerList[x++] };
for (int y = 0; y < 2; y++) // execute twice
if (x < controllerList.Count)
newList.Add(controllerList[x++]);
dict.Add(dict.Count, newList);
}
To make it more general, you could also create newList empty to start, and then change y < 2 to y < GROUP_SIZE where GROUP_SIZE is whatever sized groups you want. Could even then extract this to an extension method:
public static Dictionary<int, List<T>> ToGroupedDictionary<T>
(this IList<T> pList, int pGroupSize)
{
var dict = new Dictionary<int, List<T>>();
int x = 0;
while (x < pList.Count)
{
var newList = new List<T>();
for (int y = 0; y < pGroupSize && x < pList.Count; y++, x++)
newList.Add(pList[x]);
dict.Add(dict.Count, newList);
}
return dict;
}
And then you can do this:
var groups = new[]
{
"Item1",
"Item2",
"Item3",
"Item4",
"Item5",
"Item6",
"Item7",
"Item8"
}.ToGroupedDictionary(3);

Categories

Resources