Reputation: 32162
I have the following data
IEnumerable<Tuple<T, List<U>>> Data;
or that could be expressed also as
Dictionary<T, List<U>> GroupedA
That is given a T it might belong to one or more U. I want to invert this so I can lookup U and find all the associated T's in the structure
Dictionary<U, List<T>> GroupedB;
Trying to think of a neat LINQ expression to invert the dictionary.
EDIT
Actually the correct answer below shows that what I really want is
ILookup<U, T>
rather than
Dictionary<U, List<T>>
Upvotes: 3
Views: 244
Reputation: 174289
Try this:
Data.SelectMany(tuple => tuple.Item2.Select(u => new { U = u, T = tuple.Item1 }))
.GroupBy(x => x.U)
.ToDictionary(g => g.Key, g => g.Select(x => x.T).ToList());
Complete test case code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using FluentAssertions;
namespace StackOverflow
{
public class Class1
{
//Populating data
Dictionary<int, List<string>> GroupedA = new Dictionary<int, List<string>>();
public Class1()
{
GroupedA.Add(1, new List<string> { "1", "2", "3" });
GroupedA.Add(2, new List<string> { "1", "32", "3", "4" });
GroupedA.Add(3, new List<string> { "1", "52", "43", "4" });
}
[Fact]
public void ToDictionarySpec()
{
var data = GroupedA.Select(v => Tuple.Create(v.Key, v.Value));
var r = data.SelectMany(tuple => tuple.Item2.Select(u => new { U = u, T = tuple.Item1 }))
.GroupBy(x => x.U)
.ToDictionary(g => g.Key, g => g.Select(x => x.T).ToList());
//Printing data
var pairs = r.Select(pair => string.Format("{0} : {1}", pair.Key, string.Join(",", pair.Value)));
Console.WriteLine(string.Join(Environment.NewLine, pairs));
}
}
}
outputs
Test Name: ToDictionarySpec
Test Outcome: Passed
Result StandardOutput:
1 : 1,2,3
2 : 1
3 : 1,2
32 : 2
4 : 2,3
52 : 3
43 : 3
Upvotes: 4
Reputation: 23626
//Populating data
Dictionary<int, List<string>> GroupedA = new Dictionary<int, List<string>>();
GroupedA.Add(1, new List<string>{"1","2","3"});
GroupedA.Add(2, new List<string>{"1","32","3","4"});
GroupedA.Add(3, new List<string>{"1","52","43","4"});
//Inverting data
ILookup<string, int> GroupedB =
GroupedA.SelectMany(pair => pair.Value.Select(val => new{pair.Key, val}))
.ToLookup(pair => pair.val, pair => pair.Key);
//Printing data
var pairs = GroupedB.Select(pair => string.Format("{0} : {1}", pair.Key, string.Join(",", pair)));
Console.WriteLine (string.Join(Environment.NewLine, pairs));
prints:
1 : 1,2,3
2 : 1
3 : 1,2
32 : 2
4 : 2,3
52 : 3
43 : 3
Upvotes: 6