【问题标题】:Comparing 2 Dictionary<string, string> Instances比较 2 个 Dictionary<string, string> 实例
【发布时间】:2010-10-13 23:16:01
【问题描述】:

我想比较两个Dictionary&lt;string, string&gt; 实例的内容,而不管它们包含的项目的顺序如何。 SequenceEquals 也比较顺序,所以我先按键排序字典,然后调用SequenceEquals

有什么方法可以代替SequenceEquals 只比较内容吗?

如果没有,这是理想的方法吗?

Dictionary<string, string> source = new Dictionary<string, string>();
Dictionary<string, string> target = new Dictionary<string, string>();

source["foo"] = "bar";
source["baz"] = "zed";
source["blah"] = null;

target["baz"] = "zed";
target["blah"] = null;
target["foo"] = "bar";

// sequenceEquals will be false
var sequenceEqual = source.SequenceEqual(target);
// contentsEqual will be true
var contentsEqual = source.OrderBy(x => x.Key).SequenceEqual(target.OrderBy(x => x.Key));

【问题讨论】:

  • 这个问题包含一个很大的缺陷。没有元素在字典中的顺序之类的东西。根据定义,字典保存键值对,没有任何隐式排序。

标签: c# linq dictionary comparison


【解决方案1】:
var contentsEqual = source.DictionaryEqual(target);

// ...

public static bool DictionaryEqual<TKey, TValue>(
    this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
{
    return first.DictionaryEqual(second, null);
}

public static bool DictionaryEqual<TKey, TValue>(
    this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second,
    IEqualityComparer<TValue> valueComparer)
{
    if (first == second) return true;
    if ((first == null) || (second == null)) return false;
    if (first.Count != second.Count) return false;

    valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;

    foreach (var kvp in first)
    {
        TValue secondValue;
        if (!second.TryGetValue(kvp.Key, out secondValue)) return false;
        if (!valueComparer.Equals(kvp.Value, secondValue)) return false;
    }
    return true;
}

【讨论】:

  • 通过无序字典,您的算法可以在 O(n^2) 中运行。
  • @Yuriy: O(n^2),假设哈希码是半体面的?
  • 假设 GetHash 已实现。
  • 我承认,我不知道 Object 上的 GetHashCode 实现返回了真实的哈希码。
  • @Yuriy:如果您使用字典,那么您要么 假设哈希码是一半,或者 你确保它们是.字典中的键查找被假定为大约 O(1)。如果不是,那么您将看到全面的性能不佳,而不仅仅是我的方法。
【解决方案2】:

我不知道是否存在现有方法,但您可以使用以下方法(为简洁起见,省略了对 args 的空检查)

public static bool DictionaryEquals<TKey,TValue>(
  this Dictionary<TKey,TValue> left,
  Dictionary<TKey,TValue> right ) { 

  var comp = EqualityComparer<TValue>.Default;
  if ( left.Count != right.Count ) { 
    return false;
  }
  foreach ( var pair in left ) {
    TValue value;
    if ( !right.TryGetValue(pair.Key, out value) 
         || !comp.Equals(pair.Value, value) ) {
      return false;
    }
  } 
  return true;
}

最好添加一个重载以允许自定义EqualityComparer&lt;TValue&gt;

【讨论】:

    【解决方案3】:

    如果您使用SortedDictionary,则无需自行应用排序,使用起来会稍微容易一些:

    void Main()
    {
        var d1 = new Dictionary<string, string>
        {
            ["a"] = "Hi there!",
            ["b"] = "asd",
            ["c"] = "def"
        };
        var d2 = new Dictionary<string, string>
        {
            ["b"] = "asd",
            ["a"] = "Hi there!",
            ["c"] = "def"
        };
    
        var sortedDictionary1 = new SortedDictionary<string, string>(d1);
        var sortedDictionary2 = new SortedDictionary<string, string>(d2);
    
        if (sortedDictionary1.SequenceEqual(sortedDictionary2))
        {
            Console.WriteLine("Match!");
        }
        else
        {
            Console.WriteLine("Not match!");
        }
    }
    

    【讨论】:

      【解决方案4】:

      这将检查source中的所有Values是否存在于target中,忽略Keys

      var result = source.All(x => target.Any(y => x.Value == y.Value));
      

      【讨论】:

      • 这错过了target 具有不在source 中的附加键值对的情况
      • @JaredPar:如果target 有额外的配对,那么会发生什么?返回false 而不是true?然后额外检查长度会解决它吗?
      • 我会说如果内容不同,那么它们就不相等。长度检查将解决 target 更大但不是密钥不同的问题。
      • @JaredPar:我假设 OP 只想比较内容。 [...] that will only compare the contents?
      猜你喜欢
      • 1970-01-01
      • 2014-12-03
      • 1970-01-01
      • 2017-09-07
      • 1970-01-01
      • 1970-01-01
      • 2012-09-21
      • 2012-03-01
      • 1970-01-01
      相关资源
      最近更新 更多