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()))
Related
I have a dictionary which looks like this:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>()
{
{"a" , new List<string> { "Red","Yellow"} },
{"b" , new List<string> { "Blue","Red"} },
{"c" , new List<string> { "Green","Orange"} },
{"d" , new List<string> { "Black","Green"} },
};
I need output as a dictionary from the dict where common value in the List<string> should be the key and the value should be the list of keys.
E.g.:
Red: [a,b]
Green: [c,d]
I don't know how to solve this problem with list in dictionary as TValue.
Please explain me how to handle lists with in dictionary.
You can flattern your dictionary with SelectMany and get plain list that looks like
"a" - "Red"
"a" - "Yellow"
"b" - "Blue"
"b" = "Red"
// and so on
then group by value and build a new dictionary from those groups. Try this code:
var commonValues = dict.SelectMany(kv => kv.Value.Select(v => new {key = kv.Key, value = v}))
.GroupBy(x => x.value)
.Where(g => g.Count() > 1)
.ToDictionary(g => g.Key, g => g.Select(x => x.key).ToList());
Lots of looping... Loop over the dictionary, then loop over each value in the list.
var result = new Dictionary<string, List<string>>();
// Loop through each key/value pair in the dictionary
foreach (var kvp in dict)
{
// kvp.Key is the key ("a", "b", etc)
// kvp.Value is the list of values ("Red", "Yellow", etc)
// Loop through each of the values
foreach (var value in kvp.Value)
{
// See if our results dictionary already has an entry for this
// value. If so, grab the corresponding list of keys. If not,
// create a new list of keys and insert it.
if (!result.TryGetValue(value, out var list))
{
list = new List<string>();
result.Add(value, list);
}
// Add our key to this list of keys
list.Add(kvp.Key);
}
}
If you want to filter this by entries which have more than one item, then you can do:
result = result.Where(x => x.Value.Count > 1).ToDictionary(x => x.Key, x => x.Value);
Alternatively, you can avoid loops and use Linq instead:
// Flatten the dictionary into a set of tuples
// e.g. (a, Red), (a, Yellow), (b, Blue), (b, Red), etc
var result = dict.SelectMany(kvp => kvp.Value.Select(color => (key: kvp.Key, color)))
// Group by the value, taking the color as the elements of the group
// e.g. (Red, (a, b)), (Yellow, (a)), etc
.GroupBy(item => item.color, item => item.key)
// Filter to the ones with more than one item
.Where(group => group.Count() > 1)
// Turn it into a dictionary, taking the key of the grouping
// (Red, Green, etc), as the dictionary key
.ToDictionary(group => group.Key, group => group.ToList());
You can also use linq query syntax, which is slightly longer but avoids the mess around the SelectMany:
var result =
(
from kvp in dict
from color in kvp.Value
group kvp.Key by color into grp
where grp.Count() > 1
select grp
).ToDictionary(grp => grp.Key, grp => grp.ToList());
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());
How to merge 2 dictionaries of IDictionary<Guid, MyObject> where MyObject is a class instance?
IDictionary<Guid, MyObject> d1 = new Dictionary<Guid, MyObject>();
d1.Add(guid1, m1);
d1.Add(guid2, m2);
d1.Add(guid3, m3);
IDictionary<Guid, MyObject> d2 = new Dictionary<Guid, MyObject>();
d2.Add(guid2, m2);
d2.Add(guid3, m3);
d2.Add(guid4, m4);
IDictionary<Guid, MyObject> d3 = d1.Union(d2) ???
That in d3 there are the following entries:
guid1,m1
guid2,m2
guid3,m3
guid4,m4
d1.Concat(d2.Where( x=> !d1.Keys.Contains(x.Key)));
d1.Union(d2).GroupBy (kvp => kvp.Key).ToDictionary(kvp => kvp.Key, kvp => kvp.First().Value); out to do the trick.
IDictionary<Guid, MyObject> d1 = new Dictionary<Guid, MyObject>();
d1.Add(guid1, m1);
d1.Add(guid2, m2);
d1.Add(guid3, m3);
IDictionary<Guid, MyObject> d2 = new Dictionary<Guid, MyObject>();
d2.Add(guid2, m2);
d2.Add(guid3, m3);
d2.Add(guid4, m4);
IDictionary<Guid, MyObject> d3 =
d1.Union(d2).GroupBy (kvp => kvp.Key)
.ToDictionary (kvp => kvp.Key, kvp => kvp.First ().Value);
If you have duplicate key then you'll have to handle duplicate key with the using of where clause.
var result = d1.Union(d2.Where(k => !d1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value)
Note : It will not get duplicate key. if there will be any duplicate key than it will get d1's key.
You could try something like
d1.Concat(d2).Distinct(kv => kv.Key).ToDictionary(kv => kv.Key, kv => kv.Value)
The result of concat makes use of the fact that the dictionary is an IEnumerable<KeyvaluePair<Guid,MyObject>>
Since I do not have a compiler I just checked that Distinct cannot accept just a lambda selecting the property to be compared. However it can accept an EqualityComparer. What I often have in projects is a Generic Equality Comparer that allows to pass in lambdas which define the equality operation.
Union looks good:
http://msdn.microsoft.com/en-us/vcsharp/aa336761.aspx#union1
This will merge unique keys and unique list of values:
d1.Union(d2).GroupBy(g => g.Key).ToDictionary(pair => pair.Key, pair => pair.First().Value.Union(pair.Last().Value).ToList());
When no duplicates keys exist, the following works for 2 (or more) dictionaries:
var dictionaries = new [] { d1, d2 };
var result = dictionaries.SelectMany(dict => dict)
.ToDictionary(pair => pair.Key, pair => pair.Value);
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);
I have a C# dictionary Dictionary<MyKey, MyValue> and I want to split this into a collection of Dictionary<MyKey, MyValue>, based on MyKey.KeyType. KeyType is an enumeration.
Then I would be left with a dictionary containing key-value pairs where MyKey.KeyType = 1, and another dictionary where MyKey.KeyType = 2, and so on.
Is there a nice way of doing this, such as using Linq?
var dictionaryList =
myDic.GroupBy(pair => pair.Key.KeyType)
.OrderBy(gr => gr.Key) // sorts the resulting list by "KeyType"
.Select(gr => gr.ToDictionary(item => item.Key, item => item.Value))
.ToList(); // Get a list of dictionaries out of that
If you want a dictionary of dictionaries keyed by "KeyType" in the end, the approach is similar:
var dictionaryOfDictionaries =
myDic.GroupBy(pair => pair.Key.KeyType)
.ToDictionary(gr => gr.Key, // key of the outer dictionary
gr => gr.ToDictionary(item => item.Key, // key of inner dictionary
item => item.Value)); // value
I believe the following will work?
dictionary
.GroupBy(pair => pair.Key.KeyType)
.Select(group => group.ToDictionary(pair => pair.Key, pair => pair.Value);
So you're actually wanting a variable of type IDictionary<MyKey, IList<MyValue>>?
You could just use the GroupBy Linq function:
var dict = new Dictionary<Key, string>
{
{ new Key { KeyType = KeyTypes.KeyTypeA }, "keytype A" },
{ new Key { KeyType = KeyTypes.KeyTypeB }, "keytype B" },
{ new Key { KeyType = KeyTypes.KeyTypeC }, "keytype C" }
};
var groupedDict = dict.GroupBy(kvp => kvp.Key.KeyType);
foreach(var item in groupedDict)
{
Console.WriteLine("Grouping for: {0}", item.Key);
foreach(var d in item)
Console.WriteLine(d.Value);
}
Unless you just want to have separate collections:
Dictionary myKeyTypeColl<KeyType, Dictionary<MyKey, KeyVal>>
Dictionary <int,string> sports;
sports=new Dictionary<int,string>();
sports.add(0,"Cricket");
sports.add(1,"Hockey");
sports.add(2,"Badminton");
sports.add(3,"Tennis");
sports.add(4,"Chess");
sports.add(5,"Football");
foreach(var spr in sports)
console.WriteLine("Keu {0} and value {1}",spr.key,spr.value);
output:
Key 0 and value Cricket
Key 1 and value Hockey
Key 2 and value Badminton
Key 3 and value Tennis
Key 4 and value Chess
Key 5 and value Football