How to consolidate a Dictionary with multiple (thr

2019-06-09 04:38发布

问题:

I have a Dictionary with the following definition.

    Dictionary<int[], int> D = new Dictionary<int[], int>();

where the key is a 3 element array. I am giving this as example to simplify my scenario. (In my own code the Key is a complex class object that has a List of 3-7 elements in it for key.)

    int[] key;
    key = new int[] { 1, 1, 1 };
    D.Add(key, 1);
    key = new int[] { 1, 1, 2 };
    D.Add(key, 2);
    key = new int[] { 1, 1, 3 };
    D.Add(key, 3);
    key = new int[] { 1, 2, 4 };
    D.Add(key, 4);
    key = new int[] { 2, 1, 1 };
    D.Add(key, 5);
    key = new int[] { 2, 5, 1 };
    D.Add(key, 6);

What i want is to have a means to reduce the number of keys, ie. instead of having an array of three element I want a 2 element array as key and have all the values that are redundant be consolidated into one single value so that the resulting KeyValue pairs should look the following way. (reducing the first index for keys)

    {1 1, 6} //two instances of matching key of {1 1} resulted the value to have 1+5 =6
    {1 2, 2}
    {1 3, 3}
    {2 4, 4}
    {5 1, 6}

回答1:

First of all, your dictionary probably doesn't work as you expect - there is no default comparer for int[] type, so keys won't be unique in your dictionary (you can have two elements with 1 1 1 key for example). To get this to work you need to provide custom IEqualityComparer<int[]>. This will also be needed to make the solution to your main problem work:

public class IntArrayEqualityComparer : IEqualityComparer<int[]>
{
    public bool Equals(int[] x, int[] y)
    {
        if (x.Length != y.Length)
        {        
            return false;
        }

        return x.Zip(y, (v1, v2) => v1 == v2).All(b => b);
    }

    public int GetHashCode(int[] x)
    {
        return 0;
    }
}

So you should create your dictionary as follows:

Dictionary<int[], int> D
    = new Dictionary<int[], int>(new IntArrayEqualityComparer());

Returning to the main issue, here is how you can achieve the desired result:

var result = D
    .GroupBy(
        kvp => kvp.Key.Skip(1).ToArray(),
        new IntArrayEqualityComparer())
    .ToDictionary(
        g => g.Key,
        g => g.Sum(x => x.Value));