比较C#中的两个词典

时间:2011-07-19 19:48:06

标签: c# linq collections dictionary comparison

我有两个词典,两个都具有相同的结构和顺序(一个应该是另一个的精确复制品):Dictionary<int, ICustomInterface>我想用SequenceEqual<> <检查它们是否相等/ p>

首先,我将第一个字典转换为XML,然后将其读回以重新创建第二个字典。初步检查时,它们都是相同的。 ICustomeInterface个对象各自正确覆盖Equals方法。为了检查这一点,我迭代了两个词典的元素并进行比较。他们都是平等的。

但是当我调用SequenceEqualdictionary1.SequenceEqual(dictionary2);时,它返回false并且ICustomInterface个对象的Equals方法永远不会被调用,它总是返回false。但是,如果我这样做:

for (i = 0; i < firstDictionary.Count; i++)
   firstDictionary[i].SequenceEqual(otherSub.ItemSequence[i]);

一切都按预期工作,并且每行返回true。那么,当我简单地在字典本身上调用SequnceEqual时会发生什么?

2 个答案:

答案 0 :(得分:16)

“正在发生什么”是按顺序比较两个词典的KeyValuePair条目。字典本质上是无序的 - 你不应该依赖于条目从它们中出来的顺序。如果您使用:

firstDictionary.OrderBy(pair => pair.Key)
               .SequenceEqual(secondDictionary.OrderBy(pair => pair.Key))

我怀疑你会发现那些比赛。虽然比较它们是一种非常不愉快的方式:)

答案 1 :(得分:1)

Jon Skeet已经给出了一个很好的解释。

但是,如果您(或其他任何阅读此问题的人)想要的是一种比较词典的有效方法,这是一个简单的基于Linq的扩展,它将做到这一点:

/// <summary>
/// Compares two dictionaries for equality.
/// </summary>
/// <returns>
/// True if the dictionaries have equal contents or are both null, otherwise false.
/// </returns>
public static bool DictionaryEqual<TKey, TValue>(
    this IDictionary<TKey, TValue> dict1, IDictionary<TKey, TValue> dict2,
    IEqualityComparer<TValue> equalityComparer = null)
{
    if (dict1 == dict2)
        return true;

    if (dict1 == null | dict2 == null)
        return false;

    if (dict1.Count != dict2.Count)
        return false;

    if (equalityComparer == null)
        equalityComparer = EqualityComparer<TValue>.Default;

    return dict1.All(kvp =>
        {
            TValue value2;
            return dict2.TryGetValue(kvp.Key, out value2)
                && equalityComparer.Equals(kvp.Value, value2);
        });
}

它可能看起来有点蓬松,但我想要良好的可读性(和空测试)。

所以,如果你想要的只是一个&#34;单行&#34; ,你就已经知道这两个字典都是非空的,并且TValue类型会覆盖等于方法正确,那么你真的需要这么多(如果TValue当然是bool isEqual = dict1.Count == dict2.Count && dict1.All(kvp => { TValue value2; return dict2.TryGetValue(kvp.Key, out value2) && (kvp.Value == null ? value2 == null : kvp.Value.Equals(value2)); }); ,则无空检查):

/// <summary>
/// Compares two dictionaries for equality using a custom value equality function.
/// </summary>
/// <returns>
/// True if both dictionaries are null or both have the same set of keys and comparing
/// their respective values for each key using the <paramref name="valueEqualityFunc"/>
/// returns true, otherwise false.
/// </returns>
public static bool DictionaryEqual<TKey, TValue1, TValue2>(
    this IDictionary<TKey, TValue1> dict1, IDictionary<TKey, TValue2> dict2,
    Func<TValue1, TValue2, bool> valueEqualityFunc)
{
    if (valueEqualityFunc == null)
        throw new ArgumentNullException("valueEqualityFunc");

    if (dict1 == dict2)
        return true;

    if (dict1 == null | dict2 == null)
        return false;

    if (dict1.Count != dict2.Count)
        return false;

    return dict1.All(kvp =>
    {
        TValue2 value2;
        return dict2.TryGetValue(kvp.Key, out value2)
            && valueEqualityFunc(kvp.Value, value2);
    });
}

如果要进行比较,其中字典不必具有相同类型的值,或者如果您更喜欢使用委托或lambda表达式而不必实现IEqualityComparer,则此扩展将执行你的诀窍是:

var d1 = new Dictionary<string, string>();
var d2 = new Dictionary<string, string>();

d1.Add("key1", "dog");
d2.Add("key1", "Dog");
d1.Add("key2", "CAT");
d2.Add("key2", "cat");

bool isEqual = DictionaryEqual(d1, d2,
    (s1, s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase));

你可以看到它和以前几乎一样。

以下是一个用法示例:

isEqual

如果您运行上面的代码text_en:(recreation -"create") 将成为现实。