How to convert a 2-d array into a dictionary object - c#

I have an array of type string that looks like this:
"test1|True,test2|False,test3|False,test4|True".
This is essentially a 2d array like so
[test1][True]
[test2][False]
[test3][False]
[test4][True].
I want to convert this into a dictionary<string,bool> using linq, something like:
Dictionary<string, bool> myResults = results.Split(",".ToCharArray).ToDictionary()
any ideas?

var d = results.Split(',')
.Select(row => row.Split('|'))
.ToDictionary(srow => srow[0], srow => bool.Parse(srow[1]));

First turn your string into a proper array:
String sData = "test1|True,test2|False,test3|False,test4|True";
String[] sDataArray = sData.Split(',');
Then you can process the String[] into a dictionary:
var sDict = sDataArray.ToDictionary(
sKey => sKey.Split('|')[0],
sElement => bool.Parse(sElement.Split('|')[1])
);
The ToDictionary method takes 2 functions which extract the key and element data from the each source array element.
Here, I've extracted each half by splitting on the "|" and then used the first half as the key and the second I've parsed into a bool to use as the element.
Obviously this contains no error checking so could fail if the source string wasn't comma separated, or if each element wasn't pipe separated. So be careful with where your source string comes from. If it doesn't match this pattern exactly it's going to fail so you'll need to do some tests and validation.
Marcelo's answer is similar, but I think it's a bit more elegant.

You could try something like this:
var resultsArray = results.Split(',');
var myResults = new Dictionary<string, bool>();
foreach (var str in resultsArray)
{
var parts = str.Split('|');
myResults.Add(parts[0], bool.Parse(parts[1]));
}

Something like this should work:
var fullString = "Test,True|Test2,False";
var query = from item in fullString.Split('|')
let splitted = item.Split(',')
let value = bool.Parse(splitted[1])
select new { Key = splitted[0], Value = value };
var dict = query.ToDictionary(pair => pair.Key, pair => pair.Value);

Related

Adding more than one value to a single key in a hashtable in c#?

I'm trying to make a program where it reads strings that has a word and its meaning, for example
Book: Cover with Papers in between
Book: Reserve
And whenever I try my code I get an error because each key has to be unique. Is there a way to work around this?
Hashtable ht = new Hashtable();
var fileStream = new FileStream(#"e:\test.txt", FileMode.Open, FileAccess.Read);
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
ht.Add(line.Split(':')[0], line.Split(':')[1]);
}
}
if (ht.ContainsKey("Book"))
{
listBox1.Items.Add(ht["Book"].ToString());
}
In the general case, you could use a List<string> for the value, and just Add to it. However, you can probably simplify with LINQ via ToLookup:
var groups = File.ReadLines(path)
.Select(line => line.Split(':'))
.ToLookup(x => x[0], x => x[1].Trim());
Now you can access groups[key] which gives you all the values with that prefix, or you can foreach over groups to get each combination of .Key and values.
In terms of your code, this is:
var groups = File.ReadLines(#"e:\test.txt")
.Select(line => line.Split(':'))
.ToLookup(x => x[0], x => x[1].Trim());
foreach(var val in groups["Book"])
listBox1.Items.Add(val);
(no need to check for existence first, it just works correctly if no match)
However! You only need to do this if you still want all the values after this code, i.e. you use groups somewhere else. If you don't, you can be more frugal and just abandon the unwanted data:
var values = File.ReadLines(#"e:\test.txt")
.Where(line => line.StartsWith("Book:"))
.Select(line => line.Substring(5).Trim());
foreach(var val in values)
listBox1.Items.Add(val);
Edit: minor thing - a vexing method signature means that line.Split(':') actually creates an array every time, because params; so I usually use:
static readonly char[] Colon = {':'};
and
line.Split(Colon)
Which is measurably more efficient if it is a hot path.
Use a Dictionary where the values is a list of strings:
var myDicitonary = new Dictionary<string, List<string>>
And now, you'd do the following:
if (!myDictionary.ContainsKey(key))
{
myDicitonary.Add(key, new List<string>());
}
myDicitonary[key].Add(value);
Use a Dictionary<string, List<string>> instead of the Hashtable.
Depending on what you want to achieve, you may use a SortedList or a SortedDictionary, that you initialze with your own IComparer, which allows duplicate keys.
Have a look at these Stackoverflow posts for details:
C# Sortable collection which allows duplicate keys
Is there an alternative to Dictionary/SortedList that allows duplicates?
The drawback of this solution is, that you cannot access the elements by key, but still by index.
use Dictionary instead.
Dictionary<string, list<string>> dic = new Dictionary<string, list<string>();

Modifying duplicate Key value on entry to Dictionary (C#)

I have a requirement where I would like to use a dictionary to store "key=value" pairs, however now I need to store "duplicate" key values.
I have a line of delimited text (delimited with a pipe character ("|") which I split up into an array and then into a dictionary (see below)
string[] t = rawMessage.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries);
message = t.ToDictionary(s => s.Split('=')[0], s => s.Split('=')[1]);
This works fine if no duplicates exist but I want to store duplicate keys in a way that adjusts the key value before insertion.
example
A=1|B=2|C=3|D=4|D=5|D=5
I want the key value to be adjusted to something like:
A=1
B=2
C=3
D=4
D[1]=5
D[2]=5
So then I can pull out the entry of the 2nd and 3rd "D" entries as they have a new key value.
Each duplicate is a unqiue record, as such I would like to be able to reference then in the order they were entered. the forth entry would be D[4] for example. A suggestion on using the same key value for all the values, may/will be confusing and I may end up pulling the wrong information (but will keep it in mind).
I would like to avoid having to loop through the array beforehand, and wondered if anyone knows a way I can perform this on the ToDictionary part of the code above.
Apologies for the fairly basic explaination.
Many of the threads deal with removing dupes in dictionaries and I understand that this is not the intended use of a dictionary.
If you want to associate multiple values with a key, you could just make the value part of the pair a list:
var dict = new Dictionary<char, List<int>>();
char key = 'D';
int value = 5;
if (!dict.ContainsKey(key))
dict[key] = new List<int>();
dict[key].Add(value);
You can use GroupBy to group the result set by the key, then flatten the groupings using SelectMany, projecting the desired key using the Select method overload with index parameter:
var message = t
.Select(s => s.Split('='))
.GroupBy(s => s[0], s => s[1])
.SelectMany(g => g.Select((v, i) => new
{
Key = i == 0 ? g.Key : g.Key + "[" + i + "]",
Value = v
}))
.ToDictionary(e => e.Key, e => e.Value);
You can either use a dictionary with a collection-based value:
Dictionary<string, List<int>>
You can then use the best data structure for the job you need, but List<> is a good default.
Or you can use the Lookup<TKey, TElement> class, but this doesn't give array indexing on the value elements:
Lookup<string, int>
Which supports groupings under the key (so an enumerable of TElement). The docs for it are here.
Alternatively still, roll your own data structure, but it is very unlikely this would be required - a composite of existing things will likely work for you well enough.
Well..I'm going to a basic answer,without using LINQ. What i would do is make my own ToDictionary method, just checking if a key exists and if it does,create the new key and add it to the Dictionary, something like this:
public Dictionary<string,string> ToDictionary(string[] t)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (string s in t)
{
string[] reg = s.Split('=');
int i = 1;
while (dict.ContainsKey(reg[0]))
{
if (!reg[0].Contains('['))
reg[0] = reg[0] + "[" + i.ToString() + "]";
else
reg[0] = reg[0].Replace((i - 1).ToString(), i.ToString());
i++;
}
dict.Add(reg[0], reg[1]);
}
return dict;
}
This can easily be converted in an extension Method.
Alternative way would be to use NameValueCollection in System.Collections.Specialized. The interesting thing with NameValueCollection is that if there are duplicate values for the same key, it will keep the values in the same key as comma separated value. The key will be the same this way, but the values you might have to separate it out.
A quick sample and output is given below.
class Program
{
static void Main(string[] args)
{
NameValueCollection col = new NameValueCollection();
col.Add("A", "1");
col.Add("A", "2");
col.Add("B", "0");
col.Add("B", "1");
col.Add("B", "3");
col.Add("D", "1");
foreach (string key in col.AllKeys)
{
Console.WriteLine(key + " " + col[key] + "\n");
}
Console.ReadKey();
}
}
Output
A 1,2
B 0,1,2
D 1
Output
Like Adam Houldsworth said you can use Lookup.
Here is a snippet based on Adam Houldsworth's answer.
var str = #"A=1|B=2|C=3|D=4|D=5|D=5";
string[] t = str.Split(new[] { '|', '|' }, StringSplitOptions.RemoveEmptyEntries);
var message = t.ToLookup(s => s.Split('=')[0], s => Convert.ToInt32(s.Split('=')[1]));
var res = message.ToDictionary(i=>i.Key, x=>x.LastOrDefault());
Edit:
After reading your question again I understand you want the D=4 value also.
var res = message.SelectMany(i => i.Select((x, y) => new
{
Key = i.Key,
Value = x
})).GroupBy(q=>q.Value)
.SelectMany(x=>x.ToLookup(xx=>xx.Key, xx=>xx.Value));

Reduce code bloat when trimming an array of strings

I have a string of comma separated values, to get a string array from this I use
string[] values = value.Split(',');
I want to trim all these values by creating a new list of string and calling a foreach on the array like this
List<string> trimmedValues = new List<string>();
foreach (string str in values)
trimmedValues.Add(str.Trim());
Is there a more efficent way to do this with less code say by calling a method on the array itself?
Use linq
List<string> trimmedValues = values.Select(v => v.trim()).toList()
Try this :
var myTrimResult = "a ,b , c ".Split(',').Select(x => x.Trim());
The "myTrimResult" variable will contain trimmed elements.
To effectively reduce code bloat, I suggest to use an extension.
Declare a method like the following, in a common context in your project (or even better, in an external helper DLL to carry among different projects):
public static List<string> TrimList(this string[] array)
{
var list = new List<string>();
foreach (var s in array)
{
list.Add(s.Trim());
}
return list;
}
Now, in your code, you can simply use:
var trimmedValues = values.TrimList();
I find it more readable than using LINQ expression in code

C# Convert List<string> to Dictionary<string, string>

This may seem an odd thing to want to do but ignoring that, is there a nice concise way of converting a List<string> to Dictionary<string, string> where each Key Value Pair in the Dictionary is just each string in the List. i.e.
List = string1, string2, string3
Dictionary = string1/string1, string2/string2, string3/string3
I have done plenty of searching and there are literally dozens of examples on Stackoverflow alone of doing it in the opposite direction but not this way round.
The reason for doing this is I have two third part components and changing them is out of my hands. One returns a list of email addresses as a List<string> and the other send emails where the To parameter is a Dictionary<string, string>. The key of the dictionary is the email address and the value is their real name. However, I don't know the real name but it still works if you set the real name to the email address as well. Therefore why I want to convert a List to a Dictionary<string, string>. There are plenty of ways of doing this. A foreach loop on the list which adds a kvp to a dictionary. But I like terse code and wondered if there was a single line solution.
Try this:
var res = list.ToDictionary(x => x, x => x);
The first lambda lets you pick the key, the second one picks the value.
You can play with it and make values differ from the keys, like this:
var res = list.ToDictionary(x => x, x => string.Format("Val: {0}", x));
If your list contains duplicates, add Distinct() like this:
var res = list.Distinct().ToDictionary(x => x, x => x);
EDIT To comment on the valid reason, I think the only reason that could be valid for conversions like this is that at some point the keys and the values in the resultant dictionary are going to diverge. For example, you would do an initial conversion, and then replace some of the values with something else. If the keys and the values are always going to be the same, HashSet<String> would provide a much better fit for your situation:
var res = new HashSet<string>(list);
if (res.Contains("string1")) ...
Use this:
var dict = list.ToDictionary(x => x);
See MSDN for more info.
As Pranay points out in the comments, this will fail if an item exists in the list multiple times.
Depending on your specific requirements, you can either use var dict = list.Distinct().ToDictionary(x => x); to get a dictionary of distinct items or you can use ToLookup instead:
var dict = list.ToLookup(x => x);
This will return an ILookup<string, string> which is essentially the same as IDictionary<string, IEnumerable<string>>, so you will have a list of distinct keys with each string instance under it.
EDIT
another way to deal with duplicate is you can do like this
var dic = slist.Select((element, index)=> new{element,index} )
.ToDictionary(ele=>ele.index.ToString(), ele=>ele.element);
or
easy way to do is
var res = list.ToDictionary(str => str, str=> str);
but make sure that there is no string is repeating...again otherewise above code will not work for you
if there is string is repeating than its better to do like this
Dictionary<string,string> dic= new Dictionary<string,string> ();
foreach(string s in Stringlist)
{
if(!dic.ContainsKey(s))
{
// dic.Add( value to dictionary
}
}
By using ToDictionary:
var dictionary = list.ToDictionary(s => s);
If it is possible that any string could be repeated, either do a Distinct call first on the list (to remove duplicates), or use ToLookup which allows for multiple values per key.
You can use:
var dictionary = myList.ToDictionary(x => x);

using LINQ in C# to convert a List<string> to a List<char>

I have a list of strings in C#, and want to create a list of unique characters that are in the strings in the list, using LINQ.
I have so far worked out how to turn the List into a List, but I can't work out how to get the LINQ to go further than that.
What I have so far is as follows:
List<string> dictionary = new List<string>(someArray);
List<string[]> uniqueCharacters = dictionary.ConvertAll(s => s.Split());
I believe I need to something along the lines of
List<char> uniqueCharacters =
dictionary.ConvertAll(s => s.Split()).SelectAll(t, i=>t[i][0]);
You can use LINQ's SelectMany method, e.g.:
var list = new List<string> { "Foo", "Bar" };
var chars = list.SelectMany(s => s.ToCharArray());
var distinct = chars.Distinct();
Get your LinQ result and put it in loop, compare every char with in list of char.
foreach (string character in dictionary)
{
if (!(uniqueCharacters).Contains(character))
{
uniqueCharacters.Add(character);
}
}

Categories

Resources