简体   繁体   中英

How to Check All Values in Dictionary is same in C#?

I have a Dictionary, I want to write a method to check whether all values are same in this Dictionary. Dictionary Type:

Dictionary<string, List<string>>

List {1,2,3}`and {2,1,3} are same in my case.

I have done this previously for simple datatype values, but I can not find logic for new requirement, please help me. For simple values: MyDict.GroupBy(x => x.Value).Where(x => x.Count() > 1)

I have also written a Generic Method to compare two datatypes in this way.

// 1
            // Require that the counts are equal
            if (a.Count != b.Count)
            {
                return false;
            }
            // 2
            // Initialize new Dictionary of the type
            Dictionary<T, int> d = new Dictionary<T, int>();
            // 3
            // Add each key's frequency from collection A to the Dictionary
            foreach (T item in a)
            {
                int c;
                if (d.TryGetValue(item, out c))
                {
                    d[item] = c + 1;
                }
                else
                {
                    d.Add(item, 1);
                }
            }
            // 4
            // Add each key's frequency from collection B to the Dictionary
            // Return early if we detect a mismatch
            foreach (T item in b)
            {
                int c;
                if (d.TryGetValue(item, out c))
                {
                    if (c == 0)
                    {
                        return false;
                    }
                    else
                    {
                        d[item] = c - 1;
                    }
                }
                else
                {
                    // Not in dictionary
                    return false;
                }
            }
            // 5
            // Verify that all frequencies are zero
            foreach (int v in d.Values)
            {
                if (v != 0)
                {
                    return false;
                }
            }
            // 6
            // We know the collections are equal
            return true;

Implement an IEqualityComparer for List<string> that compares two list based on their content. Then just use Distinct on Values and check the count:

dictionary.Values.Distinct(new ListEqualityComparer()).Count() == 1

This should do the trick

var lists = dic.Select(kv => kv.Value.OrderBy(x => x)).ToList();
var first = lists.First();
var areEqual = lists.Skip(1).All(hs => hs.SequenceEqual(first));

You'll need to add some checks to make this work for the empty case.

...or if you want to take @Selman's approach here's an implementation of the IEqualityComparer :

class SequenceComparer<T>:IEqualityComparer<IEnumerable<T>>
{
    public bool Equals(IEnumerable<T> left, IEnumerable<T> right)
    {
        return left.OrderBy(x => x).SequenceEqual(right.OrderBy(x => x));
    }
    public int GetHashCode(IEnumerable<T> item)
    {
        //no need to sort because XOR is commutative
        return item.Aggregate(0, (acc, val) => val.GetHashCode() ^ acc);
    }
}

You could make a variant of this combining the best of both approaches using a HashSet<T> that might be considerably more efficient in the case that you have many candidates to test:

HashSet<IEnumerable<int>> hs = new HashSet<IEnumerable<int>>(new SequenceComparer<int>());
hs.Add(dic.First().Value);
var allEqual = dic.All(kvp => !hs.Add(kvp.Value));

This uses the feature of HashSets that disallows adding more than one item that is considered equal with an item already in the set. We make the HashSet use the custom IEqualityComparer above...

So we insert an arbitrary item from the dictionary before we start, then the moment another item is allowed into the set (ie hs.Add(kvp.Value) is true ), we can say that there's more than one item in the set and bail out early. .All does this automatically.

Selman22's answer works perfectly - you can also do this for your Dictionary<string, List<string>> without having to implement an IEqualityComparer yourself:

var firstValue = dictionary.Values.First().OrderBy(x => x);
return dictionary.Values.All (x => x.OrderBy(y => y).SequenceEqual(firstValue));

We compare the first value to every other value, and check equality in each case. Note that List<string>.OrderBy(x => x) simply sorts the list of strings alphabetically.

它不是最快的解决方案,但它适用于我:

bool AreEqual = l1.Intersect(l2).ToList().Count() == l1.Count() && l1.Count() == l2.Count();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM