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

名单 A:

1, 2, 3, 4

名单 B:

2, 5

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

例如,像 A 这样的东西包含(a = > a.id = B.id) ?

140018 次浏览

If you didn't care about performance, you could try:

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

But I would try this first:

a.Intersect(b).Any()

You can Intersect the two lists:

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

I've profiled Justins two solutions. a.Any(a => b.Contains(a)) is fastest.

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
}
}
}

I write a faster method for it can make the small one to set. But I test it in some data that some time it's faster that Intersect but some time Intersect fast that my code.

    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);
}

The Intersect calls Set that have not check the second size and this is the Intersect's code.

        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;

The difference in two methods is my method use HashSet and check the count and Intersect use set that is faster than HashSet. We dont warry its performance.

The test :

   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();
}
}

I use this to count:

int cnt = 0;


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

Sorry, if this is irelevant, but will return list with matches using FindAll() in case you need this:

        private bool IsContain(string cont)
{
List<string> ListToMatch= new List<string>() {"string1","string2"};


if (ListToMatch.ToArray().Any(cont.Contains))
{
return false;
}
else
return true;
}

And usage:

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

The final list contains only the matched elements string1 and string2 from list to check. Can easy be switched to int List.

For faster and short solution you can use HashSet instead of List.

a.Overlaps(b);

Overlaps documentation

This method is an O(n) instead of O(n^2) with two lists.

You can check if a list is inside of another list with this

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));