Reputation: 29
I have this:
var color = new Dictionary<string, List<string>>();
color.Add("Blue", new List<string>() { "1", "2" });
color.Add("Green", new List<string>() { "2", "3" });
color.Add("Red", new List<string>() { "1", "3" });
color.Add("Black", new List<string>() { "3" });
color.Add("Yellow", new List<string>() { "1" });
I would to convert this to a
Dictionary<string, List<string>>
that looks like this:
Key: 1, Value: Blue, Red, Yellow
Key: 2, Value: Blue, Green
Key: 3, Value: Green, Red, Black
Tried:
var test = color.GroupBy(x => x.Value.FirstOrDefault())
.ToDictionary(g => g.Key, g => g.Select(x => x.Key).ToList());
However this only works for one item so ("FirstOrDefault()"), i only get
Key: 1, Value: Blue, Red, Yellow
How could i do this? I could loop through the values (distinct) and there loop through the keys and check if value exist then build up a new one but i would like to avoid this and use lamda.
Seen many example of this but with no list of string as values but only a string.
Upvotes: 1
Views: 501
Reputation: 112772
Basically, I had the same idea as @SamIAm and @kanders84152. I just want to make a little improvement and to add an explanation:
var test = color
.SelectMany(c => c.Value.Select(v => new { Number = v, Color = c.Key }))
.GroupBy(a => a.Number, a => a.Color)
.ToDictionary(g => g.Key, g => g.ToList());
The main difference of my solution is that the GroupBy
part extracts the color from the anonymous type instead of the ToDictionary
part.
First the .SelectMany(c => c.Value.Select(v => new { Number = v, Color = c.Key }))
part flattens the nested lists to an enumeration of an anonymous type with numbers and color names.
The original dictionary entries
"Blue", { "1", "2" }
"Green", { "2", "3" }
"Red", { "1", "3" }
"Black", { "3" }
"Yellow", { "1" }
become
{ Number: "1", Color: "Blue" }
{ Number: "2", Color: "Blue" }
{ Number: "2", Color: "Green" }
{ Number: "3", Color: "Green" }
{ Number: "1", Color: "Red" }
{ Number: "3", Color: "Red" }
{ Number: "3", Color: "Black" }
{ Number: "1", Color: "Yellow" }
.GroupBy(a => a.Number, a => a.Color)
then re-groups these values by the number and takes the color as value
"1", { "Blue", "Red", "Yellow" }
"2", { "Blue", "Green" }
"3", { "Green" "Red", "Black" }
This is almost the desired result, except that we have an IGrouping<string, string>
(where the groups represent a key and an enumeration of values)
instead of a Dictionary<string, List<string>>
. Finally .ToDictionary(g => g.Key, g => g.ToList())
creates the desired dictionary with the same structure.
Upvotes: 3
Reputation: 31206
If I were you I'd flatten it first
var colorflat = color
.SelectMany(c => c.Value.Select(n => new {Color=c.Key, Number=n}));
and then I'd group to the new format
var test = colorflat
.GroupBy(c => c.Number)
.ToDictionary(c => c.Key, c => c.Select(x => x.Color).ToList());
Upvotes: 0
Reputation: 1341
Try this:
var test = color
.SelectMany(x => x.Value.Select(v =>
new
{
Color = x.Key,
Integer = v
}))
.GroupBy(x => x.Integer)
.ToDictionary(x => x.Key, x => x.Select(y => y.Color).ToList());
Upvotes: 6