【问题标题】:How to check list A contains any value from list B?如何检查列表 A 是否包含列表 B 中的任何值?
【发布时间】:2012-09-04 18:43:57
【问题描述】:

列表A:

1, 2, 3, 4

列表 B:

2, 5

如何检查列表 A 是否包含列表 B 中的任何值?

例如类似 A.contains(a=>a.id = B.id)?

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    如果你不关心性能,你可以试试:

    a.Any(item => b.Contains(item))
    // or, as in the column using a method group
    a.Any(b.Contains)
    

    但我会先试试这个:

    a.Intersect(b).Any()
    

    【讨论】:

    • 像魅力一样工作。由于您是第一个回答者,所以我将您的标记为答案。谢谢。
    • 您不能在列表和 lambda 中都使用 'a'。 a.Any(a => b.Contains(a))。我建议使用方法组而不是 a.Any(b.Contains)
    • 我之前使用的是“Any..Contains”方法,但对于我的问题,Intersect 方法的工作速度要快一个数量级。感谢您的选择!
    【解决方案2】:

    你可以Intersect这两个列表:

    if (A.Intersect(B).Any())
    

    【讨论】:

      【解决方案3】:

      我介绍了 Justins 的两种解决方案。 a.Any(a => b.Contains(a)) 最快

      using System;
      using System.Collections.Generic;
      using System.Linq;
      
      namespace AnswersOnSO
      {
          public class Class1
          {
              public static void Main(string []args)
              {
      //            How to check if list A contains any value from list B?
      //            e.g. something like A.contains(a=>a.id = B.id)?
                  var a = new List<int> {1,2,3,4};
                  var b = new List<int> {2,5};
                  var times = 10000000;
      
                  DateTime dtAny = DateTime.Now;
                  for (var i = 0; i < times; i++)
                  {
                      var aContainsBElements = a.Any(b.Contains);
                  }
                  var timeAny = (DateTime.Now - dtAny).TotalSeconds;
      
                  DateTime dtIntersect = DateTime.Now;
                  for (var i = 0; i < times; i++)
                  {
                      var aContainsBElements = a.Intersect(b).Any();
                  }
                  var timeIntersect = (DateTime.Now - dtIntersect).TotalSeconds;
      
                  // timeAny: 1.1470656 secs
                  // timeIn.: 3.1431798 secs
              }
          }
      }
      

      【讨论】:

      • 如果 A 和 B 的大小和大小相似怎么办?这种性能分析似乎取决于这些列表的相对大小
      • 我用两组 500 个随机整数尝试了@radbyx 的解决方案,AnyIntersect 快得多。 code.dcoder.tech/files/code/5dcc1bf388de5305e2f24b9e/… Any 大约是 4 秒,Intersect 大约是 185 秒。
      • 这只是表明Any 的最佳情况在数据相交时更快,因为它可以提前返回。然而,Any 的最坏情况是当列表没有交集时速度较慢,因为它是O(N^2)
      【解决方案4】:

      我写了一个更快的方法,因为它可以使小的设置。但是我在一些数据中对其进行了测试,有时它比 Intersect 更快,但有时 Intersect 比我的代码快。

          public static bool Contain<T>(List<T> a, List<T> b)
          {
              if (a.Count <= 10 && b.Count <= 10)
              {
                  return a.Any(b.Contains);
              }
      
              if (a.Count > b.Count)
              {
                  return Contain((IEnumerable<T>) b, (IEnumerable<T>) a);
              }
              return Contain((IEnumerable<T>) a, (IEnumerable<T>) b);
          }
      
          public static bool Contain<T>(IEnumerable<T> a, IEnumerable<T> b)
          {
              HashSet<T> j = new HashSet<T>(a);
              return b.Any(j.Contains);
          }
      

      Intersect 调用 Set 没有检查第二个大小,这是 Intersect 的代码。

              Set<TSource> set = new Set<TSource>(comparer);
              foreach (TSource element in second) set.Add(element);
              foreach (TSource element in first)
                  if (set.Remove(element)) yield return element;
      

      两种方法的区别是我的方法使用HashSet并检查计数,Intersect使用比set快的set。我们不担心它的性能。

      测试:

         static void Main(string[] args)
          {
              var a = Enumerable.Range(0, 100000);
              var b = Enumerable.Range(10000000, 1000);
              var t = new Stopwatch();
              t.Start();
              Repeat(()=> { Contain(a, b); });
              t.Stop();
              Console.WriteLine(t.ElapsedMilliseconds);//490ms
      
              var a1 = Enumerable.Range(0, 100000).ToList();
              var a2 = b.ToList();
              t.Restart();
              Repeat(()=> { Contain(a1, a2); });
              t.Stop();
      
              Console.WriteLine(t.ElapsedMilliseconds);//203ms
      
              t.Restart();
              Repeat(()=>{ a.Intersect(b).Any(); });
              t.Stop();
              Console.WriteLine(t.ElapsedMilliseconds);//190ms
      
              t.Restart();
              Repeat(()=>{ b.Intersect(a).Any(); });
              t.Stop();
              Console.WriteLine(t.ElapsedMilliseconds);//497ms
      
              t.Restart();
              a.Any(b.Contains);
              t.Stop();
              Console.WriteLine(t.ElapsedMilliseconds);//600ms
      
          }
      
          private static void Repeat(Action a)
          {
              for (int i = 0; i < 100; i++)
              {
                  a();
              }
          }
      

      【讨论】:

        【解决方案5】:

        我用这个来计算:

        int cnt = 0;
        
        foreach (var lA in listA)
        {
            if (listB.Contains(lA))
            {
                cnt++;
            }
        }
        

        【讨论】:

        • 不要求计数。这是非常低效的命令式代码。
        • 为了这个答案,可能需要更多解释,例如为什么您选择使用计数而不是布尔值。这确实完成了工作。
        【解决方案6】:

        抱歉,如果这无关紧要,但如果您需要,将使用 FindAll() 返回包含匹配项的列表:

                private bool IsContain(string cont)
            {
                List<string> ListToMatch= new List<string>() {"string1","string2"};
        
                if (ListToMatch.ToArray().Any(cont.Contains))
                {
                    return false;
                }
                else
                    return true;
            }
        

        及用法:

        List<string> ListToCheck = new List<string>() {"string1","string2","string3","string4"};
        List<string> FinalList = ListToCheck.FindAll(IsContain);
        

        最终列表仅包含要检查的列表中匹配的元素 string1 和 string2。 可以轻松切换到 int List。

        【讨论】:

          【解决方案7】:

          对于更快更短的解决方案,您可以使用HashSet 而不是List

          a.Overlaps(b);
          

          Overlaps documentation

          这个方法是一个 O(n) 而不是 O(n^2) 的两个列表。

          【讨论】:

            【解决方案8】:

            你可以用这个检查一个列表是否在另一个列表中

            var list1 = new List<int> { 1, 2, 3, 4, 6 };
            var list2 = new List<int> { 2, 3 };
            bool a = list1.Any(c => list2.Contains(c));
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-06-13
              • 1970-01-01
              • 2012-07-04
              • 2010-12-03
              • 1970-01-01
              • 1970-01-01
              • 2020-05-18
              相关资源
              最近更新 更多