Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse many-to-many Dictionary<key, List<value>>

Tags:

Actually my previous question got me thinking and I realized that reversing a Dictionary is not trivial. What is the most elegant and readable way to do it?

Same scenario student Many to Many with Classes

original Dicitonary<int, List<int>> where the key is studentId and the Value is a List<int> that contains classId and want to revert to Dictionary<classId, List<studentId>>

Thanks

Update: Actually I just tested Luke and Bruno's solutions and they return the right amount of classed whoever they all have the same student, will update as i go along.

like image 501
roundcrisis Avatar asked Aug 24 '09 23:08

roundcrisis


2 Answers

Slightly different way (a bit more comprehensible to my brain anyway :) ...

var newDict = new Dictionary<int, List<int>>(); var dict = new Dictionary<int, List<int>>(); dict.Add( 1, new List<int>() { 1, 2, 3, 4, 5 } ); dict.Add( 2, new List<int>() { 1, 2, 3, 4, 5 } ); dict.Add( 3, new List<int>() { 1, 2, 6 } ); dict.Add( 4, new List<int>() { 1, 6, 7 } ); dict.Add( 5, new List<int>() { 8 } );  var newKeys = dict.Values.SelectMany( v => v ).Distinct();  foreach( var nk in newKeys ) {    var vals = dict.Keys.Where( k => dict[k].Contains(nk) );    newDict.Add( nk, vals.ToList() ); } 
like image 20
JP Alioto Avatar answered Jan 22 '23 21:01

JP Alioto


To reverse a dictionary is very easy:

var newDic = oldDic.ToDictionary(x => x.Value, x => x.Key); 

That's all.

Now, your question is different. It is about reversing a many-to-many relationship, established on a dictionary.

So, let's say you have Dictionary<TEntity1, IEnumerable<TEntity2>>. The idea is to extract from this the "middle table" of the many-to-many relationship. Then you can regroup it by the other side, and retransform into a dictionary.

For the first part, we will use the overload of SelectMany that

"Projects each element of a sequence to an IEnumerable<T>, flattens the resulting sequences into one sequence, and invokes a result selector function on each element therein."

var table =     dict.SelectMany(         x => x.Value,         (dictEntry, entryElement) => new                {                       Entity1 = dictEntry.Key,                       Entity2 = entryElement                }     ); 

So, now you just have to regroup this table the way you want, and then convert it to a dictionary.

 var newDict =      table          .GroupBy(x => x.Entity2,                   x => x.Entity1,                   (entity2, entity1) => new {entity1, entity2})          .ToDictionary(x => x.entity2, x => x.entity1); 
like image 139
Bruno Reis Avatar answered Jan 22 '23 21:01

Bruno Reis