17

I have a dictionary: Dictionary<int,int>. I want to get new dictionary where keys of original dictionary represent as List<int>. This is what I mean:

var prices = new Dictionary<int,int>();

The prices contain the following data:

1   100
2   200
3   100
4   300

I want to get the IList<Dictionary<int,List<int>>>:

int      List<int>
100      1,3
200      2
300      4

How can I do this?

Dave New
  • 38,496
  • 59
  • 215
  • 394
user1260827
  • 1,498
  • 6
  • 31
  • 53

6 Answers6

31
var prices = new Dictionary<int, int>();
prices.Add(1, 100);
prices.Add(2, 200);
prices.Add(3, 100);
prices.Add(4, 300);

Dictionary<int,List<int>> test  = 
                   prices.GroupBy(r=> r.Value)
                  .ToDictionary(t=> t.Key, t=> t.Select(r=> r.Key).ToList());
Habib
  • 219,104
  • 29
  • 407
  • 436
  • Thanks, but, values contains all object, I want only keys from original dictionary – user1260827 Nov 16 '12 at 04:56
  • @user1260827, sorry missed one thing, you may try the query now. I just tried it in VS and its working – Habib Nov 16 '12 at 05:06
  • can anyone explain what the "ToDictionary" does here? – burhan Mar 05 '14 at 18:54
  • @burhan, it creates a [Dictionary](http://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx), you can read more about [Enumerable.ToDictionary](http://msdn.microsoft.com/en-us/library/bb549277(v=vs.110).aspx) – Habib Mar 05 '14 at 22:31
4

You can use GroupBy.

Dictionary<int,List<int>> groups = 
             prices.GroupBy(x => x.Value)
                   .ToDictionary(x => x.Key, x => x.Select(i => i.Key).ToList());
Asif Mushtaq
  • 13,010
  • 3
  • 33
  • 42
3

Here is my reply. When the dictionaries get large, you will likely find the GroupBy() extension methods less efficient than you would like, as they provide many guarantees that you don't need, such as retaining order.

public static class DictionaryExtensions 
{
    public static IDictionary<TValue,List<TKey>> Reverse<TKey,TValue>(this IDictionary<TKey,TValue> src) 
    {
        var result = new Dictionary<TValue,List<TKey>>();

        foreach (var pair in src) 
        {
            List<TKey> keyList;

            if (!result.TryGetValue(pair.Value, out keyList)) 
            {
                keyList = new List<TKey>();
                result[pair.Value] = keyList;
            }

            keyList.Add(pair.Key);
        }

        return result;
    }
}

And an example to use in LinqPad:

void Main()
{
    var prices = new Dictionary<int, int>();
    prices.Add(1, 100);
    prices.Add(2, 200);
    prices.Add(3, 100);
    prices.Add(4, 300);

    // Dump method is provided by LinqPad.
    prices.Reverse().Dump();
}
Phil Martin
  • 466
  • 4
  • 4
2

You can use GroupBy followed by the Func<TSource, TKey>, Func<TSource, TElement> overload of Enumerable.ToDictionary:

var d = prices.GroupBy(x => x.Value).ToDictionary(x => x.Key, x => x.ToList());
lc.
  • 113,939
  • 20
  • 158
  • 187
1

You can use Lookup instead.

var prices = new Dictionary<int, int> { {1, 100}, { 2, 200 }, { 3, 100 }, { 4, 300 } };
ILookup<int, int> groups = prices.ToLookup(x => x.Value, y => y.Key);
foreach (var group in groups)
{
    foreach (var item in group)
    {
        Console.WriteLine(item);
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
alanextar
  • 1,094
  • 13
  • 16
0

In particular case, when we use the .NET framework 2.0, we can do as follows:

var prices = new Dictionary<int, int>();
prices.Add(1, 100);
prices.Add(2, 200);
prices.Add(3, 100);
prices.Add(4, 300);

Dictionary<int, List<int>> grouping = new Dictionary<int, List<int>>();

var enumerator = prices.GetEnumerator();
while (enumerator.MoveNext())
{
    var pair = enumerator.Current;
    if (!grouping.ContainsKey(pair.Value))
        grouping[pair.Value] = new List<int>();
    grouping[pair.Value].Add(pair.Key);
}
Alexandre N.
  • 2,594
  • 2
  • 28
  • 32