在c#中测试字典之间的相等性

时间:2010-09-27 13:43:07

标签: c# dictionary equality

假设字典键和值的equals和hash方法正确实现,那么测试两个字典相等的最简洁有效的方法是什么?

在这种情况下,如果它们包含相同的一组键(顺序并不重要),则说两个词典是相同的。对于每个这样的键,它们都同意该值。

这里有一些我提出的方法(可能还有更多):

public bool Compare1<TKey, TValue>(
    Dictionary<TKey, TValue> dic1, 
    Dictionary<TKey,TValue> dic2)
{
    return dic1.OrderBy(x => x.Key).
        SequenceEqual(dic2.OrderBy(x => x.Key));
}

public bool Compare2<TKey, TValue>(
    Dictionary<TKey, TValue> dic1, 
    Dictionary<TKey, TValue> dic2)
{
    return (dic1.Count == dic2.Count && 
        dic1.Intersect(dic2).Count().
        Equals(dic1.Count));
}

public bool Compare3<TKey, TValue>(
    Dictionary<TKey, TValue> dic1, 
    Dictionary<TKey, TValue> dic2)
{
    return (dic1.Intersect(dic2).Count().
        Equals(dic1.Union(dic2).Count()));
}

9 个答案:

答案 0 :(得分:91)

dic1.Count == dic2.Count && !dic1.Except(dic2).Any();

答案 1 :(得分:12)

这实际上取决于平等意味着什么。

此方法将测试两个字典包含具有相同值的相同键(假设两个字典都使用相同的IEqualityComparer<TKey>实现)。

public bool CompareX<TKey, TValue>(
    Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2)
{
    if (dict1 == dict2) return true;
    if ((dict1 == null) || (dict2 == null)) return false;
    if (dict1.Count != dict2.Count) return false;

    var valueComparer = EqualityComparer<TValue>.Default;

    foreach (var kvp in dict1)
    {
        TValue value2;
        if (!dict2.TryGetValue(kvp.Key, out value2)) return false;
        if (!valueComparer.Equals(kvp.Value, value2)) return false;
    }
    return true;
}

答案 2 :(得分:3)

您可以使用linq进行键/值比较:

public bool Compare<TKey, TValue>(Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue dict2)
{
    IEqualityComparer<TValue> valueComparer = EqualityComparer<TValue>.Default;

    return  dict1.Count == dict2.Count &&
            dict1.Keys.All(key => dict2.ContainsKey(key) && valueComparer.Equals(dict1[key], dict2[key]));
}

答案 3 :(得分:1)

@Allen's answer

bool equals = a.Intersect(b).Count() == a.Union(b).Count()

是关于数组的,但就使用IEnumerable<T>方法而言,它也可以用于Dictionary<K,V>

答案 4 :(得分:1)

我认为接受的答案是正确的,基于我在smarthelp中为Except方法阅读的内容:&#34;通过使用默认的相等比较器来比较值来产生两个序列的集合差异。&#34;但我发现这不是一个好的答案。

考虑以下代码:

Dictionary<string, List<string>> oldDict = new Dictionary<string, List<string>>()
    {{"001A", new List<string> {"John", "Doe"}},
     {"002B", new List<string> {"Frank", "Abignale"}},
     {"003C", new List<string> {"Doe", "Jane"}}};
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>()
    {{"001A", new List<string> {"John", "Doe"}},
     {"002B", new List<string> {"Frank", "Abignale"}},
     {"003C", new List<string> {"Doe", "Jane"}}};

bool equal = oldDict.Count.Equals(newDict.Count) && !oldDict.Except(newDict).Any();
Console.WriteLine(string.Format("oldDict {0} newDict", equal?"equals":"does not equal"));
equal = oldDict.SequenceEqual(newDict);
Console.WriteLine(string.Format("oldDict {0} newDict", equal ? "equals" : "does not equal"));

Console.WriteLine(string.Format("[{0}]", string.Join(", ", 
    oldDict.Except(newDict).Select(k => 
        string.Format("{0}=[{1}]", k.Key, string.Join(", ", k.Value))))));

这导致以下结果:

oldDict does not equal newDict
oldDict does not equal newDict
[001A=[John, Doe], 002B=[Frank, Abignale], 003C=[Doe, Jane]]

正如你所看到的,&#34; oldDict&#34;和&#34; newDict&#34;设置完全相同。并且建议的解决方案和对SequenceEqual的调用都不能正常工作。我想知道它是否是Except使用延迟加载或者为Dictionary设置比较器的方式的结果。 (虽然,查看结构和参考解释表明它应该。)

这是我提出的解决方案。请注意,我使用的规则如下:如果两个字典包含相同的键并且每个键的值匹配,则两个字典相等。键和值必须按相同的顺序排列。我的解决方案可能不是最有效的,因为它依赖于遍历整个键集。

private static bool DictionaryEqual(
    Dictionary<string, List<string>> oldDict, 
    Dictionary<string, List<string>> newDict)
{
    // Simple check, are the counts the same?
    if (!oldDict.Count.Equals(newDict.Count)) return false;

    // Verify the keys
    if (!oldDict.Keys.SequenceEqual(newDict.Keys)) return false;

    // Verify the values for each key
    foreach (string key in oldDict.Keys)
        if (!oldDict[key].SequenceEqual(newDict[key]))
            return false;

    return true;
}

如果出现以下情况,请查看结果如何变化: 关键顺序不一样。 (返回false)

newDict = new Dictionary<string, List<string>>()
    {{"001A", new List<string> {"John", "Doe"}},
     {"003C", new List<string> {"Doe", "Jane"}},
     {"002B", new List<string> {"Frank", "Abignale"}}};

和 键顺序匹配,但值不匹配(返回false)

newDict = new Dictionary<string, List<string>>()
    {{"001A", new List<string> {"John", "Doe"}},
     {"002B", new List<string> {"Frank", "Abignale"}},
     {"003C", new List<string> {"Jane", "Doe"}}};

如果序列顺序无关紧要,可以将函数更改为以下内容,但可能会影响性能。

private static bool DictionaryEqual_NoSort(
    Dictionary<string, List<string>> oldDict,
    Dictionary<string, List<string>> newDict)
{
    // Simple check, are the counts the same?
    if (!oldDict.Count.Equals(newDict.Count)) return false;

    // iterate through all the keys in oldDict and
    // verify whether the key exists in the newDict
    foreach(string key in oldDict.Keys)
    {
        if (newDict.Keys.Contains(key))
        {
            // iterate through each value for the current key in oldDict and 
            // verify whether or not it exists for the current key in the newDict
            foreach(string value in oldDict[key])
                if (!newDict[key].Contains(value)) return false;
        }
        else { return false; }
    }

    return true;
}

检查DictionaryEqual_NoSort是否使用以下newDict(DictionaryEquals_NoSort返回true):

newDict = new Dictionary<string, List<string>>()
    {{"001A", new List<string> {"John", "Doe"}},
     {"003C", new List<string> {"Jane", "Doe"}},
     {"002B", new List<string> {"Frank", "Abignale"}}};     

答案 5 :(得分:1)

除了@Nick Jones答案之外,您还需要以与顺序无关的相同方式来实现gethashcode。我建议像这样:

public override int GetHashCode()
{
        int hash = 13;
        var orderedKVPList = this.DictProp.OrderBy(kvp => kvp.key)
        foreach (var kvp in orderedKVPList)
        {
                 hash = (hash * 7)  + kvp.Key.GetHashCode();
                 hash = (hash * 7)  + kvp.value.GetHashCode();
        }
        return hash;
}

答案 6 :(得分:0)

如果两个词典包含相同的键,但顺序不同,它们是否应该被认为是相同的?如果没有,那么应该通过同时运行枚举器来比较字典。这可能比通过一个字典枚举并查找另一个字典中的每个元素更快。如果你已经知道相同的词典将以相同的顺序排列它们的元素,那么这种双重枚举可能是要走的路。

答案 7 :(得分:0)

在OP问题中它确实说同等性测试不仅要涵盖密钥的匹配,还要涵盖它们的值“在这种情况下,如果它们包含相同的密钥集,则说两个字典相等(顺序)并不重要),对于每一个这样的密钥,他们都同意价值。“

我是否遗漏了某些内容或标记的答案https://stackoverflow.com/a/3804852/916121仅检查尺寸和按键是否相等而不是它们的值?

我会在答案旁边发布这个但是无法解决如何将其添加为评论,抱歉。

答案 8 :(得分:0)

对于嵌套字典和列表,我在此处结合了以下几个想法:https://gist.github.com/NullVoxPopuli/f95baaa48b4e9854dcfe(此处发布的代码太多)~100行