【问题标题】:C# compare dictionaries for equalityC#比较字典是否相等
【发布时间】:2018-09-02 23:18:49
【问题描述】:

如何最有效地比较两个字典是否相等? -- 除了对键的暴力迭代,尝试查找和比较值

var d1 = new Dictionary<string,int>();
d1.Add("a",2);
d1.Add("b",1);
d1.Add("c",1);

var d2 = new Dictionary<string,int>();
d2.Add("c",1);
d2.Add("b",1);
d2.Add("a",2);

如何最有效地比较平等?

不是这样的蛮力:

static bool CompareDictionaries(Dictionary<string,int> d1, Dictionary<string,int> d2)
{
    if (d1.Count != d2.Count) return false;
    foreach(string key in d1.Keys)
    {
        if (!d2.ContainsKey(key)) return false;
        if (d1[key] != d2[key]) return false;
    }
    return true;
}

【问题讨论】:

  • 如果其中一个字典区分大小写而另一个不区分大小写,您希望发生什么?在这种情况下,您现有的代码将无法“工作”(例如,它会说某些字典是相同的,而实际上它们不是)-我只是在检查这是否是故意的。
  • @mjwills 你必须通过比较器对吗?
  • @ParrishHusband 这取决于 OP 想要什么。 最有可能他们想要stackoverflow.com/a/9547410/34092
  • @baltostar: 是否假设字典包含相同的键

标签: c# dictionary compare


【解决方案1】:

如果Dictionary键相同,可以使用HashSet进行比较:

var set1 = new HashSet<int>(dictionary1.Values);
var set2 = new HashSet<int>(dictionary2.Values);

然后可以使用Union、Intersect、HashSet暴露的除外。另外,你可以使用这个:

bool isEqual = set1.SetEquals(set2);

根据您的情况,基准测试是(HashSet vs Dictionary)here

【讨论】:

  • 任何类似这样的方法,如果Values 看到,都会有这种类型的错误。
【解决方案2】:

再加上自定义的SequenceEquals 扩展,您可以指定如何将键和值与以下内容进行比较:

public static bool Equals<TKey, TValue>(IDictionary<TKey, TValue> a, IDictionary<TKey, TValue> b,
    IComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer)
{
    if (ReferenceEquals(a, b))
        return true;

    if (b == null || a == null)
        return false;

    if (a.Count != b.Count)
        return false;

    var aOrdered = a.OrderBy(k => k.Key, keyComparer);
    var bOrdered = b.OrderBy(k => k.Key, keyComparer);

    return aOrdered.SequenceEqual(bOrdered, valueComparer);
}

扩展名:

public static bool SequenceEqual<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> first, IEnumerable<KeyValuePair<TKey, TValue>> second, IEqualityComparer<TValue> valueComparer)
{
    if (valueComparer == null) valueComparer = EqualityComparer<TValue>.Default;
    if (first == null) throw new ArgumentNullException(nameof(first));
    if (second == null) throw new ArgumentNullException(nameof(second));

    using (IEnumerator<KeyValuePair<TKey, TValue>> e1 = first.GetEnumerator())
    using (IEnumerator<KeyValuePair<TKey, TValue>> e2 = second.GetEnumerator())
    {
        while (e1.MoveNext())
        {
            if (!(e2.MoveNext() && valueComparer.Equals(e1.Current.Value, e2.Current.Value))) return false;
        }
        if (e2.MoveNext()) return false;
    }
    return true;
}

您可以在 OP 的特定 Dictionary&lt;string,int&gt; 示例中调用:

var areEqual = Equals(d1, d2, StringComparer.OrdinalIgnoreCase, EqualityComparer<int>.Default);

【讨论】:

    猜你喜欢
    • 2021-09-14
    • 2013-10-09
    • 1970-01-01
    • 2023-03-11
    • 2012-10-03
    • 2015-03-13
    • 2015-09-16
    相关资源
    最近更新 更多