C# Dictionary Composition - c#

Let's say I have an arbitray list of A
class A
{
string K {get;set;}
string V {get;set;}
}
...
List<A> theList = ...
Is there an easy way to compose a dictionary from theList? (something like the following)
Dictionary<string, string> dict = magic(x => x.K, x => x.V, theList)
I don't want to write the following code:
var d = new Dictionary<string, string>
foreach(var blah in theList)
d[blah.K] = blah.V

There's this: Enumerable.ToDictionary.
You use it like this:
Dictionary<string, string> dict = theList.ToDictionary(e => e.K, e => e.V);

If the list is an IEnumerable<A> then most definitely. You would use the ToDictionary extension method on the Enumerable class in the System.Linq namespace in .NET 3.5 and beyond like so:
Dictionary<string, string> d = theList.ToDictionary(a => a.K, a => a.V);
Which will give you a Dictionary where the key is the value in the K property, and the value is the value in the V property.

var dict = theList.Cast<A>().ToDictionary(a => a.K, a => a.V);

Dictionary<string, string> dict = theList.ToDictionary( x => x.K , x=> x.V);

Enumarable.ToDictionary<TSource,TKey> is what you are looking for:
theList.ToDictionary(x => x.K, x => x.V);

Dictionary<string,string> dict = new Dictionary<string,string>();
theList.ForEach( param => dict[param.K] = param.V );
A little shorter, but still basically a for-each loop. I like the ToDictionary() solution better.

Related

connect values with the same key in Dictionary<string, string>

I need to combine 2 dictionary. they have the same key (KKK) with different values:
Dictionary<string, string> dic1 = ...Load***();
Dictionary<string, string> dic2 = ...Load***();
dic1:
...
[29] {[RCP, 555501001]}
[30] {[KKK, 04611105012042000120]}
...
dic2:
...
[49] {[SUM, 85737]}
[50] {[KKK, 04611701040040000180]}
...
Union:
Dictionary<string, string> dicUnion= dic1.Union(dic2).OrderBy(k => k.Key).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
result:
ThrowArgumentException: The item with the same key has already been added.
I have connect values with the same key in union Dictionary:
...
[29] {[RCP, "555501001"]}
[30] {[KKK, "04611105012042000120 04611701040040000180"]}
[31] {[SUM, "85737"]}
...
If you really want to use LINQ in this case(i'd prefer a loop):
var dicUnion = dic1.Concat(dic2)
.GroupBy(kv => kv.Key)
.ToDictionary(g => g.Key, g => String.Join(" ", g.Select(kv => kv.Value)));
This will merge both dictionaries but don't care about common keys or different values.
I need to combine 2 dictionary, they have the same key (KKK) with
different values
Ok, if you only want to create a dictionary of common keys:
var union = from kv1 in dic1
join kv2 in dic2
on kv1.Key equals kv2.Key into keyGroup
where keyGroup.Any()
select new KeyValuePair<string, string>(kv1.Key, string.Join(" ", keyGroup.Select(kv => kv.Value)));
Dictionary<string, string> dicUnion = union.ToDictionary(kv => kv.Key, kv => kv.Value);
But instead of concatenating values which have the same key in both dictionaries, i'd use a different approach. Use a Lookup<TKey, TValue>. For example:
var keyLookup = dic1.Concat(dic2).ToLookup(kv => kv.Key, kv => kv.Value);
Now you can do wahtever you want with the values, f.e. create a List<string>:
List<string> values = keyLookup["KKK"].ToList();
I'd use a simple loop to add / append items
Dictionary<string, string> dicUnion = new Dictionary<string, string>(dic1);
foreach(var item in dic2)
{
if(dicUnion.ContainsKey(item.Key))
{
dicUnion[item.Key] += " " + item.Value;
}
else
{
dicUnion.Add(item.Key, item.Value);
}
}
Just try like this;
var intersectedItems = dic1.Where(x => dic2.ContainsKey(x.Key)).Select(x => new
{
Key = x.Key,
Value = x.Value + " " + dic2[x.Key]
}).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var dicUnion = dic1.Where(x => !intersectedItems.ContainsKey(x.Key))
.Union(dic2.Where(x => !intersectedItems.ContainsKey(x.Key)))
.Union(intersectedItems).OrderBy(k => k.Key)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
If you want to connect ONLY values with the same key, you can use IEnumerable.Join method like this:
var res = dic1.Join(dic2, o1 => o1.Key, o2 => o2.Key, (o1, o2) => new { o1.Key, Value1 = o1.Value, Value2 = o2.Value});
The arguments are the second IEnumerable, key selectors and result selector. In my snippet I create anonymous class but you can create whatever structure you want. The result is again IEnumerable, you can either iterate on or use its ToList(), ToArray(), etc method.
EDIT: after reading comments to other posts I understand you want to get something like this:
dic1.Concat(dic2)
.ToLookup(o => o.Key, o => o.Value)
.ToDictionary(o => o.Key, o => string.Join(" ", o.Distinct()))

Get a filtered Dictionary from a Dictionary using LINQ

I have a dictionary of type (string, string) which is a list of groups and their IDs. I need the 2nd dictionary which should not have five groups (which I know). Can anyone help me in framing the select in LinQ which I can use to create this sub dictionary?
var myDic = new Dictionary<string,string>();
myDic.Add("1","One");
myDic.Add("2","Two");
myDic.Add("3","Three");
myDic.Add("4","Four");
//myDic.Dump();
var exclusions = new []{"2","3"};
var newDict = myDic.Where(x=> !exclusions.Contains(x.Key))
.ToDictionary(x=> x.Key, x=> x.Value);
//newDict.Dump();
var groups = new List<string>();
// Fill your groups
var yourDict = new Dictionary<string, string>();
//fill your dict.
var filteredDict = yourDict.Where(a => !groups.Contains(a.Key)).ToDictionary(k=>k.Key,v=>v.Value);
I think this should to the trick:
Dictionary<string, string> myDic;
...
var badGroups = new[] { "badGroup1", "badGroup2", ... };
var my2ndDic = myDic
.Where(e => !badGroups.Contains(e.Key))
.ToDictionary(e => e.Key, e.Value);
I suppose what you missed was the .ToDictionary() method.

Using LINQ to build a Dictionary from a List of delimited strings

I have a list of strings that look like this:
abc|key1|486997
def|key1|488979
ghi|key2|998788
gkl|key2|998778
olz|key1|045669
How can I use LINQ and ToDictionary to produce a Dictionary<string, List<string>> that looks like
key1 : { abc|key1|486997, def|key1|488979, olz|key1|045669 }
key2 : { ghi|key2|998788, gkl|key2|998778 }
Basically I want to be able to extract the second element as the key use ToDictionary() to create the dictionary in one go-round.
I'm currently doing this ..
var d = new Dictionary<string, List<string>>();
foreach(var l in values)
{
var b = l.Split('|');
var k = b.ElementAtOrDefault(1);
if (!d.ContainsKey(k))
d.Add(k, new List<string>());
d[k].Add(l);
}
I've seen the questions on building dictionaries from a single string of delimited values, but I'm
wondering if there's an elegant way to do this when starting with a list of delimited strings instead.
var list = new []
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var dict = list.GroupBy(x => x.Split('|')[1])
.ToDictionary(x => x.Key, x => x.ToList());
You can also transform it to a lookup (that is very similary to a Dictionary<K,IEnumerable<V>>) in one shot:
var lookup = list.ToLookup(x => x.Split('|')[1]);
var data = new[]
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var dictionary = data.Select(row => row.Split('|'))
.GroupBy(row => row[1])
.ToDictionary(group => group.Key, group => group);
If your data is guaranteed to be consistent like that, you could do something like this:
var data = new[]
{
"abc|key1|486997",
"def|key1|488979",
"ghi|key2|998788",
"gkl|key2|998778",
"olz|key1|045669"
};
var items = data
.GroupBy(k => k.Split('|')[1])
.ToDictionary(k => k.Key, v => v.ToList());

what is the best way to convert one dictionary to another

i have one dictionary that has entries that looks like this:
dictionary["ABC.123"] = "Test"
dictionary["DEF.123"] = "Test2"
dictionary["EFG.123"] = "Test3"
dictionary["EFG.343"] = "Test3"
dictionary["ABC.456"] = "Test"
and i want to create a new dictionary that looks like this: (basically parse out the beginning string before the "." and create that as the key and use the same value.
dictionary["ABC"] = "Test"
dictionary["DEF"] = "Test2"
dictionary["EFG"] = "Test3"
as you can see: there is always a 1 to 1 mapping between the first part of the key in the first dictionary to the value so there will be no clashes
what is the easiest way using LINQ to convert to create the second dictionary from the first ??
I can loop through each record manually and parse out the new key and create each new record but i figured there was a LINQ way of doing it
var newDict = dictionary.GroupBy(kvp => kvp.Key.Remove(kvp.Key.IndexOf('.')))
.ToDictionary(grp => grp.Key, grp => grp.First().Value);
Although a plain foreach is probably going to be more readable and efficient:
var newDict = new Dictionary<string, string>();
foreach (var kvp in dictionary)
{
newDict[kvp.Key.Remove(kvp.Key.IndexOf('.'))] = kvp.Value;
}
A simple approach is to use the Select method to generate your desired KeyValuePair in conjuntion with ToDictionary
var response = dictionary
.Select(kvp => new KeyValuePair<string, string>(kvp.Key.Remove(kvp.Key.IndexOf('.')), kvp.Value))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var dict2 = dictionary.GroupBy(x => x.Key.Split('.')[0])
.ToDictionary(g => g.Key, g => g.First().Value);

How can I Remove items from dictionary using lambda expression

I am not into LINQ solutions,
I am using simple predicat to determine if the key should be removed,
For example if the dictionary is construct like Dictionary<int, int>,
so how should I remove all the entries with negative data
I am prefer to use the same dictionary, not to create new one,
I don't have preformance issues
Is there a way to do it, without using LINQ, but using Lambda expressions?
I didn't want solutions in LINQ because no one is using them in my project, didn't want to be the first.., but because I saw the LINQ solutions look better, I will use them them..
The simplest way is probably to create a new dictionary, if that's okay for you:
var newDictionary = oldDictionary.Where(pair => pair.Value >= 0)
.ToDictionary(pair => pair.Key,
pair => pair.Value);
If you have to mutate the existing dictionary (e.g. because several other objects have reference to the same dictionary) you'd need to build a list of keys to remove, then remove them afterwards:
var toRemove = dictionary.Where(pair => pair.Value < 0)
.Select(pair => pair.Key)
.ToList();
foreach (var key in toRemove)
{
dictionary.Remove(key);
}
EDIT: I've just noticed the first sentence: "I am not into LINQ solutions". If that means you don't want to use a LINQ solution, here's the by-hand version:
List<int> toRemove = new List<int>();
foreach (KeyValuePair<int, int> pair in dictionary)
{
if (pair.Value < 0)
{
toRemove.Add(pair.Key);
}
}
foreach (var key in toRemove)
{
dictionary.Remove(key);
}
... but if you can use LINQ, I'd encourage you do. My second solution is equivalent to the "by-hand" version, but more readable IMO.
By merely using lambda expression:
foreach (var i in myDict.Where(d => (d.Value < 0 || d.key <0)).ToList() )
{
myDict.Remove(i.Key);
}
var toRemove = dict.Keys.Where(predicate).ToArray();
foreach (var key in toRemove) {
dict.Remove(key);
}
Well if you add
namespace MMExtensions
{
public static class DictionaryExtensions
{
public delegate bool Predicate<TKey, TValue>(KeyValuePair<TKey, TValue> d);
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Filter<TKey, TValue>(
this Dictionary<TKey, TValue> hashtable, Predicate<TKey, TValue> p)
{
foreach (KeyValuePair<TKey, TValue> value in hashtable.ToList().Where(value => !p(value)))
hashtable.Remove(value.Key);
}
}
}
And you had some dataset as dictionary:
Dictionary<string, int> d =
new Dictionary<string, int> {{"v", -3}, {"val1", 1}, {"val2", 2}};
Then you could use:
d.Filter(delegate(KeyValuePair<string, int> kv) { return kv.Value >= 0; });
d.Filter(kv => kv.Value >= 0);// or as lambda
Do you want to remove the items from that dictionary, or are you happy to use a new dictionary without those items included?
var d = new Dictionary<int,int>();
var newDict = d.Where(entry => entry.Value >= 0).ToDictionary(entry => entry.Key, entry => entry.Value);
Easiest one:
Dictionary<long, long> dict...
Dictionary<long, long> result = dict.Were(x => x.Value >= 0).ToDictionary(x => x.Key, x => x.Value);
Or just loop over all in 'for' in reverse order and remove invalid ones.
I know you said you are not into Linq, but I could not contain myself with the following solution, plus it is still useful if you read the title of your question. This is probably the most elegant solution to your problem:
dictionary.Where(pair => pair.Value < 0)
.Select(pair => {
dictionary.Remove(pair.Key);
return pair.Key;
});

Categories