【问题标题】:Merging a key value pair List while removing duplicates C#在删除重复项的同时合并键值对列表 C#
【发布时间】:2018-05-23 22:22:58
【问题描述】:
var a1 = new List<KeyValuePair<TKey, TValue>>();
var a2 = new List<KeyValuePair<TKey, TValue>>();

我有上面这两个键值对列表。我想在删除重复项的同时合并它们。我很确定我可以通过使用 LINQ 来做到这一点,但是我看到的示例并不直接适用,因为它们没有指定从 List&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;List&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; 的完整过程。如果两个列表包含相同的键,它们也将具有相同的值,因此在合并时保留哪一个并不重要。

【问题讨论】:

  • 定义“重复”——是他们有相同的键,还是相同的键和对象?如果它是“相同的键”,如果您多次使用特定键,但每次使用不同的 RandomObject - 您如何选择要选择的键?
  • @CamiloTerevinto 鉴于这个问题,我假设它是List&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; - 希望作者能够确认
  • 是的,它是一个 List>。抱歉,我对这些类型的对象不熟悉。 @CamiloTerevinto
  • 别担心,已经解决了
  • 具有相同键的对象也将具有相同的值。我会使用常规列表,但我正在处理其他人的代码。 @CamiloTerevinto

标签: c# list linq dictionary


【解决方案1】:

如果(如上所述)您不介意选择哪个副本,那么:

var result = a1.Concat(a2)
               .GroupBy(x => x.Key)
               .Select(g => g.First())
               .ToList();

或者,如果您有很多项目,更好的方法是使用(更有效的)DistinctBy 实现。这个(或多或少)来自MoreLinq

public static class LinqEx
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer = null)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));

        return _(); IEnumerable<TSource> _()
        {
            var knownKeys = new HashSet<TKey>(comparer);
            foreach (var element in source)
            {
                if (knownKeys.Add(keySelector(element)))
                    yield return element;
            }
        }

    }
}

然后

var result = a1.Concat(a2)
               .DistinctBy(x => x.Key)
               .ToList();

【讨论】:

  • 您不能使用GroupBy 的resultSelector 形式而不是单独的Select 吗? GroupBy(kv =&gt; kv.Key, (k, kvg) =&gt; kvg.First()) 最后你还需要ToList(),因为答案是List
  • @NetMage 是的,可能。我更喜欢单独的Select 的清晰度。 ToList 已添加。谢谢。
  • 我推测GroupBy 解决方案的效率可能低于DistinctBy 的主要原因是分离出Select。在内部,GroupBy 使用自定义的 HashSet 等效项,应该与 DistinctBy 一样高效。
  • @NetMage GroupBy 必须累积整个组,而不仅仅是第一个遇到的项目。当在小序列上使用时分裂头发,但在具有许多欺骗的大量项目上使用时,它会有所作为。可能是。我可能会测试。
  • 我推测DistinctBy 中的HashSet.Add(不要误会,我喜欢,虽然我的没有错误检查)大约等于Lookup 中的收集时间。
【解决方案2】:

你是对的,你可以在 Linq 中做到这一点。但是,您必须小心如何在 TValue 上实现相等(当然,您也必须小心 TKey,但您说这些是字符串,所以相等是明确定义的)。

void Main()
{
    var a1 = new List<KeyValuePair<string, int>>();
    var a2 = new List<KeyValuePair<string, int>>();

    a1.Add(new KeyValuePair<string, int>("A", 1));
    a1.Add(new KeyValuePair<string, int>("B", 2));
    a1.Add(new KeyValuePair<string, int>("C", 3));
    a1.Add(new KeyValuePair<string, int>("D", 4));


    a2.Add(new KeyValuePair<string, int>("B", 2));
    a2.Add(new KeyValuePair<string, int>("E", 5));
    a2.Add(new KeyValuePair<string, int>("C", 33));

    var distinct = a1.Union(a2).Distinct();

    foreach(var kv in distinct)
    {
        Console.WriteLine($"{kv.Key}={kv.Value}");
    }
}

这将打印以下结果:

A=1
B=2
C=3
D=4
E=5
C=33

【讨论】:

  • Union 是一个“集合并集”,意思是在并集之后,不能有重复。因此,Distinct 是多余的。
  • 参见the docs for Enumerable.Union : "返回值 : 一个 IEnumerable 包含两个输入序列中的元素,不包括重复项 。”
【解决方案3】:

如果您创建一个字典并遍历您的两个列表并将它们添加到字典中会怎样?字典不能有相同的键,所以在尝试添加时使用 try catch。

Dictionary<TKey,TValue> myDictionary = new Dictionary();

//Iterate over list
//add try catch to attempt to add key and value to the dictionary.

【讨论】:

    【解决方案4】:

    假设“两个列表包含相同的键,它们也将具有相同的值”您可以这样做:

    var a3 = new List<KeyValuePair<TKey, TValue>>();
    a3.AddRange(a1);
    a3.AddRange(a2);
    var a3 = a3.Distinct().ToList();
    

    或:

    var a3 = a1.Union(a2).ToList();
    

    【讨论】:

      猜你喜欢
      • 2013-04-23
      • 1970-01-01
      • 2019-08-09
      • 2019-05-17
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多