如何在C#中检查字典中的所有值是否相同?

3

我有一个字典,希望编写一个方法来检查该字典中的所有值是否相同。

字典类型:

Dictionary<string, List<string>>

在我的情况下,{1,2,3}和{2,1,3}是相同的。

我之前已经针对简单数据类型的值做过这个操作,但是我找不到处理新需求的逻辑,请帮帮我。 对于简单值: MyDict.GroupBy(x => x.Value).Where(x => x.Count() > 1)

我还编写了一种通用方法,以此方式比较两种数据类型。

// 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;

[1,2,3][1,2,3,3] 是相同的吗? - spender
不,物品数量应该相同。 - Vivek Jain
4个回答

6

实现一个 IEqualityComparerList<string>,它按照其内容比较两个列表。然后只需对 Values 使用 Distinct 并检查计数:

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

2
我在我的回答中提供了比较器的实现,请随意参考。 - spender

3

这应该可以解决问题。

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));

您需要添加一些检查以使其适用于空情况。

...或者如果您想采取@Selman的方法,这里是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);
    }
}

你可以尝试将两种方法的优点结合起来,使用 HashSet<T> 来进行测试,这样在需要测试多个候选项的情况下,效率会更高:
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));

这里使用了HashSet的特性,它不允许添加一个已经在集合中存在的等效项。我们使HashSet使用上面自定义的IEqualityComparer......

因此,在开始之前,我们向字典插入一个任意项,一旦另一个项被允许进入集合(即hs.Add(kvp.Value)true),我们就可以说集合中有多个项并且提前退出。 .All会自动执行此操作。


不错的解决方案,但我只能接受一个解决方案。 - Vivek Jain

1
Selman22的答案完美地解决了问题 - 您也可以对您的Dictionary<string, List<string>>执行此操作,而无需自己实现IEqualityComparer:
var firstValue = dictionary.Values.First().OrderBy(x => x);
return dictionary.Values.All (x => x.OrderBy(y => y).SequenceEqual(firstValue));

我们将第一个值与每个其他值进行比较,并在每种情况下检查相等性。请注意,List<string>.OrderBy(x => x) 仅按字母顺序对字符串列表进行排序。

0

这不是最快的解决方案,但对我来说可行:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接