【问题标题】:Combine two Dictionaries with LINQ将两个字典与 LINQ 结合
【发布时间】:2011-02-04 23:03:36
【问题描述】:

我的问题已被标记为可能与此问题重复:How to combine two dictionaries without looping?

我相信我的问题是不同的,因为我问的是如何以特定方式组合两个字典:我想要 Dictionary1 中的所有项目以及 Dictionary2 中不在 Dictionary1 中的所有项目(即键不存在)。

我有两本这样的字典:

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

d1["a"] = 1;
d1["b"] = 2;
d1["c"] = 3;

d2["a"] = 11;
d2["e"] = 12;
d2["c"] = 13;

我想将它们组合成一个新的字典(从技术上讲,它不必是字典,它可能只是 KeyValuePairs 的序列),这样输出包含来自 d1 的所有 KeyValuePairs 和只有来自 d2 的 KeyValuePairs,其 Key 没有出现在 d1 中。

概念上:

var d3 = d1.Concat(d2.Except(d1))

但这给了我来自 d1 和 d2 的所有元素。

看起来应该很明显,但我一定遗漏了什么。

【问题讨论】:

  • 这个问题不是那个问题的重复。这个问题询问如何组合两个字典 d1 和 d2,以便生成的字典包含 d1 中的所有项目以及 d2 中尚未在 d1 中的所有项目。另一个问题是询问,答案解释了如何在没有任何额外条件的情况下组合两个字典。

标签: c# .net linq dictionary


【解决方案1】:

默认情况下使用Except 时,它使用默认的相等比较器,对于KeyValuePair 类型,它同时比较键和值。你可以用这种方法代替:

var d3 = d1.Concat(d2.Where(kvp => !d1.ContainsKey(kvp.Key)));

【讨论】:

    【解决方案2】:
    var d3 = d1.Concat(d2.Where(kvp => ! d1.ContainsKey(kvp.Key)))
               .ToDictionary(x => x.Key, x => x.Value);
    

    这对我有用。

    【讨论】:

      【解决方案3】:

      我不知道这是否是 LinQ 中的新功能,但这正是 .Union() 所做的:

      var d3 = d1.Union(d2);
      

      当然,对于字典,您必须提供自定义相等比较器以仅匹配键:

      class KeyValuePairComparer<TKey, TValue> : IEqualityComparer<KeyValuePair<TKey, TValue>>
      {
          public bool Equals(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y)
          {
              return x.Key.Equals(y.Key);
          }
          public int GetHashCode(KeyValuePair<TKey, TValue> x)
          {
              return x.GetHashCode();
          }
      }
      

      然后:

      var d3 = d1.Union(d2, new KeyValuePairComparer<string, object>());
      

      以您的示例为例,输出将是(在 C# 交互中测试):

      > d1.Union(d2, new KeyValuePairComparer<string, object>())
      UnionIterator { { "a", 1 }, { "b", 2 }, { "c", 3 }, { "e", 12 } }
      

      注意区别:

      > d2.Union(d1, new KeyValuePairComparer<string, object>())
      UnionIterator { { "a", 11 }, { "e", 12 }, { "c", 13 }, { "b", 2 } }
      

      【讨论】:

        【解决方案4】:

        Jon Skeet(和往常一样)有一个扩展方法允许你这样做:Can I specify my explicit type comparator inline?

        【讨论】:

        【解决方案5】:

        您也可以使用自己的IEqualityComparer。示例如下:

        public class MyComparer : IEqualityComparer<KeyValuePair<string,string>> {
            public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y) {
                return x.Key.Equals(y.Key);
            }
        
            public int GetHashCode(KeyValuePair<string, string> obj) {
                return obj.Key.GetHashCode();
            }
        }
        
        ...
        
        Dictionary<string, string> d1 = new Dictionary<string, string>();
        d1.Add("A", "B");
        d1.Add("C", "D");
        
        Dictionary<string, string> d2 = new Dictionary<string, string>();
        d2.Add("E", "F");
        d2.Add("A", "D");
        d2.Add("G", "H");
        
        MyComparer comparer = new MyComparer();
        
        var d3 = d1.Concat(d2.Except(d1, comparer));
        foreach (var a in d3) {
            Console.WriteLine("{0}: {1}", a.Key, a.Value);
        }
        

        【讨论】:

        • 谢谢!这是一个非常酷的方法以及马克的方法。我看到我可以使用 IEqualityComparer,但我想知道是否有更简单的方法。
        • 通常对于 KEY 比较之类的快速操作,LINQ 可能是要走的路,但如果您需要更复杂的东西(并且需要重用它),IEqualityComparer 可能会更好,尤其是如果作为扩展方法实现。
        【解决方案6】:

        另一个使用您自己的IEqualityComparer 的解决方案就像@bitxwise 和@DaveShaw 的答案一样,但不使用Except(),这使它更简单一些:

        var d3 = d1.Concat(d2).Distinct(new MyComparer());
        

        【讨论】:

          猜你喜欢
          • 2017-07-23
          • 1970-01-01
          • 1970-01-01
          • 2012-04-19
          • 1970-01-01
          • 1970-01-01
          • 2021-03-30
          • 2012-09-20
          • 1970-01-01
          相关资源
          最近更新 更多