"Grouping" dictionary by value
Asked Answered
N

6

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?

Nan answered 16/11, 2012 at 4:45 Comment(0)
C
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());
Cow answered 16/11, 2012 at 4:51 Comment(4)
Thanks, but, values contains all object, I want only keys from original dictionaryNan
@user1260827, sorry missed one thing, you may try the query now. I just tried it in VS and its workingCow
can anyone explain what the "ToDictionary" does here?Semanteme
@burhan, it creates a Dictionary, you can read more about Enumerable.ToDictionaryCow
U
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());
Unamuno answered 16/11, 2012 at 4:48 Comment(0)
Y
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();
}
Yetta answered 16/11, 2012 at 5:21 Comment(0)
M
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());
Mahan answered 16/11, 2012 at 4:51 Comment(0)
I
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);
    }
}
Inquiry answered 8/9, 2020 at 4:57 Comment(0)
D
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);
}
Dramatization answered 29/9, 2015 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.