CoderBrien
CoderBrien

Reputation: 693

Linq aggregate dictionary into new dictionary

class Key { string s; int i; }

Given a Dictionary<Key,int> I want a new Dictionary<string,int> that is a mapping of the minimum dictionary value for each Key.s over all keys.

I feel like this should be easy but I just can't get it.

Thanks

clarification:

var dict = new Dictionary<Key,int>();
dict.Add(new Key("a", 123), 19);
dict.Add(new Key("a", 456), 12);
dict.Add(new Key("a", 789), 13);
dict.Add(new Key("b", 998), 99);
dict.Add(new Key("b", 999), 11);

and I want to produce the dictionary:

 "a" -> 12
 "b" -> 11

hope that helps.

Upvotes: 0

Views: 2237

Answers (2)

Slai
Slai

Reputation: 22876

A more generic method to skip the Lookup that is created by .GroupBy :

    public static Dictionary<K, V> aggregateBy<T, K, V>(
        this IEnumerable<T> source,
        Func<T, K> keySelector,
        Func<T, V> valueSelector,
        Func<V, V, V> aggregate,
        int capacity = 0,
        IEqualityComparer<K> comparer = null)
    {
        var dict = new Dictionary<K, V>(capacity, comparer);
        foreach (var t in source)
        {
            K key = keySelector(t);
            V accumulator, value = valueSelector(t);
            if (dict.TryGetValue(key, out accumulator))
                value = aggregate(accumulator, value);
            dict[key] = value;
        }
        return dict;
    }

Sample use:

    var dict = new Dictionary<Tuple<string,int>, int>();
    dict.Add(Tuple.Create("a", 123), 19);
    dict.Add(Tuple.Create("a", 456), 12);
    dict.Add(Tuple.Create("a", 789), 13);
    dict.Add(Tuple.Create("b", 998), 99);
    dict.Add(Tuple.Create("b", 999), 11);

    var d = dict.aggregateBy(p => p.Key.Item1, p => p.Value, Math.Min);

    Debug.Print(string.Join(", ", d));        // "[a, 12], [b, 11]"

Upvotes: 1

caesay
caesay

Reputation: 17223

I'm not clear on exactly what you're trying to do, but you can do a mapping from one dictionary to another with .Select(... and/or .ToDictionary(...

For example:

Dictionary<Key, int> original = ...
Dictionary<string, int> mapped = original.ToDictionary((kvp) => kvp.Key.s, (kvp) => kvp.Key.i);

If you improve your question to be more clear, I'll improve my answer.

EDIT: (question was clarified)

var d = dict.GroupBy(kvp => kvp.Key.s).ToDictionary(g => g.Key, g => g.Min(k => k.Value));

You want to group by the key s property, then select the minimum of the dictionary value as the new dictionary value.

Upvotes: 3

Related Questions