【问题标题】:get common elements in lists in C#在 C# 中获取列表中的常见元素
【发布时间】:2019-02-19 00:44:07
【问题描述】:

我有两个排序列表如下:

var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };

我希望输出为:{1, 1, 2}

如何在 C# 中做到这一点? 有没有使用 Linq 的方法?

【问题讨论】:

标签: c# linq


【解决方案1】:

使用Intersect:

 var commonElements = list1.Intersect(list2).ToList();

【讨论】:

  • 你会如何反转这个?即获取不常见的元素。
  • @AshBurlaczenko - 你所说的不常见是什么意思?你的意思是Except??
  • @Manoj: list1.Except(list2).ToList();
  • @MahmoudGamal:相交输出是 {1,2} 但我想要 {1, 1, 2}。
  • 你的解决方案不符合他的要求,它输出 {1,2} no {1,1,2}
【解决方案2】:

额外的 1 表示您不能使用 Intersect,因为它返回一个集合。

这里有一些代码可以满足你的需要:

var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };

var grouped1 =
    from n in list1
    group n by n
    into g
    select new {g.Key, Count = g.Count()};

var grouped2 =
    from n in list2
    group n by n
    into g
    select new {g.Key, Count = g.Count()};

var joined =
    from b in grouped2
    join a in grouped1 on b.Key equals a.Key
    select new {b.Key, Count = Math.Min(b.Count, a.Count)};

var result = joined.SelectMany(a => Enumerable.Repeat(a.Key, a.Count));

CollectionAssert.AreEquivalent(new[] {1, 1, 2}, result);

【讨论】:

    【解决方案3】:

    这很好用:

    var list1 = new List<int>() { 1, 1, 1, 2, 3 };
    var list2 = new List<int>() { 1, 1, 2, 2, 4 };
    
    var lookup1 = list1.ToLookup(x => x);
    var lookup2 = list2.ToLookup(x => x);
    
    var results = lookup1.SelectMany(l1s => lookup2[l1s.Key].Zip(l1s, (l2, l1) => l1));
    

    【讨论】:

    • 应该是公认的解决方案。虽然@Austin Salonen 的回答有效,但这个解决方案要优雅得多。更简洁,相对更容易理解。
    【解决方案4】:

    虽然@Austin Salonen 的solution 和@Enigmativity 的solution 都适用于任何给定的列表,但它们都没有利用OP 的条件,即列表是排序

    鉴于两个列表都是有序的,我们可以在O(n + m) 时间进行搜索,其中 n 和 m 是每个列表的长度。不完全确定以前的解决方案的性能如何,但肯定比O(n + m) 慢。

    基本上我们只是遍历两个列表,根据比较检查移动一个或两个枚举数。

    var results = new List<int>();
    var e1 = list1.GetEnumerator();
    var e2 = list2.GetEnumerator();
    var hasNext = e1.MoveNext() && e2.MoveNext();
    
    while (hasNext) {
        var value1 = e1.Current;
        var value2 = e2.Current;
    
        if (value1 == value2) {
            results.Add(value1);
            hasNext = e1.MoveNext() && e2.MoveNext();
        } else if (value1 < value2) {
            hasNext = e1.MoveNext();
        } else if (value1 > value2) {
            hasNext = e2.MoveNext();
        }
    }
    

    就是这样!如果没有找到匹配项,results 将是一个空列表。 请注意,这假设两个列表都按升序排列。如果它是下降的,只需翻转 &lt;&gt; 运算符。

    【讨论】:

      【解决方案5】:

      我回答这个问题迟了,这可能会对未来的访问者有所帮助。

                  List<int> p = new List<int> { 1, 1, 1, 2, 3 };
                  List<int> q = new List<int> { 1, 1, 2, 2, 4 };
                  List<int> x = new List<int>();
                  for (int i = 0; i < p.Count; i++ )
                  {
                      if (p[i] == q[i])
                      {
                          x.Add(p[i]);
                      }
                  }
      

      【讨论】:

      • 这不能回答问题。位置匹配只是侥幸。 OP 在事件之后而不是位置之后。
      猜你喜欢
      • 2021-04-10
      • 2018-09-27
      • 1970-01-01
      • 2018-07-08
      • 2020-04-13
      • 1970-01-01
      • 2017-06-14
      • 2018-09-11
      相关资源
      最近更新 更多