LINQ 查询,查找列表中的项是否包含在另一个列表中

我有以下密码:

List<string> test1 = new List<string> { "@bob.com", "@tom.com" };
List<string> test2 = new List<string> { "joe@bob.com", "test@sam.com" };

我需要删除 test2中有@bob.com 或@tom.com 的人。

我试过这样做:

bool bContained1 = test1.Contains(test2);
bool bContained2 = test2.Contains(test1);

但是 bContained2 = true。我不希望循环遍历每个列表,而是使用 Linq 查询来检索数据。BContained1与我在下面创建的 Linq 查询的条件相同:

List<string> test3 = test1.Where(w => !test2.Contains(w)).ToList();

上面的查询处理精确匹配,但不处理部分匹配。

我已经查看了其他查询,但是我可以找到与 Linq 类似的查询。任何你能告诉我的主意或任何地方都会对我很有帮助。

204442 次浏览

No need to use Linq like this here, because there already exists an extension method to do this for you.

Enumerable.Except<TSource>

http://msdn.microsoft.com/en-us/library/bb336390.aspx

You just need to create your own comparer to compare as needed.

var test2NotInTest1 = test2.Where(t2 => test1.Count(t1 => t2.Contains(t1))==0);

Faster version as per Tim's suggestion:

var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t2.Contains(t1)));

Try the following:

List<string> test1 = new List<string> { "@bob.com", "@tom.com" };
List<string> test2 = new List<string> { "joe@bob.com", "test@sam.com" };
var output = from goodEmails in test2
where !(from email in test2
from domain in test1
where email.EndsWith(domain)
select email).Contains(goodEmails)
select goodEmails;

This works with the test set provided (and looks correct).

something like this:

List<string> test1 = new List<string> { "@bob.com", "@tom.com" };
List<string> test2 = new List<string> { "joe@bob.com", "test@sam.com" };


var res = test2.Where(f => test1.Count(z => f.Contains(z)) == 0)

Live example: here

var output = emails.Where(e => domains.All(d => !e.EndsWith(d)));

Or if you prefer:

var output = emails.Where(e => !domains.Any(d => e.EndsWith(d)));
List<string> test1 = new List<string> { "@bob.com", "@tom.com" };
List<string> test2 = new List<string> { "joe@bob.com", "test@sam.com", "bets@tom.com" };


var result = (from t2 in test2
where test1.Any(t => t2.Contains(t)) == false
select t2);

If query form is what you want to use, this is legible and more or less as "performant" as this could be.

What i mean is that what you are trying to do is an O(N*M) algorithm, that is, you have to traverse N items and compare them against M values. What you want is to traverse the first list only once, and compare against the other list just as many times as needed (worst case is when the email is valid since it has to compare against every black listed domain).

from t2 in test we loop the email list once.

test1.Any(t => t2.Contains(t)) == false we compare with the blacklist and when we found one match return (hence not comparing against the whole list if is not needed)

select t2 keep the ones that are clean.

So this is what I would use.

I think this would be easiest one:

test1.ForEach(str => test2.RemoveAll(x=>x.Contains(str)));
List<string> l = new List<string> { "@bob.com", "@tom.com" };
List<string> l2 = new List<string> { "joe@bob.com", "test@bob.com" };
List<string> myboblist= (l2.Where (i=>i.Contains("bob")).ToList<string>());
foreach (var bob in myboblist)
Console.WriteLine(bob.ToString());

For those who came after reading heading of the question :

bool doesL1ContainsL2 = l1.Intersect(l2).Count() == l2.Count;

L1 and L2 are both List<T>

A simple explanation is : If resulting Intersection of two iterables has the same length as that of the smaller list (L2 here) ,then all the elements must be there in bigger list (L1 here)


For those who read the whole question

var list3 =  test2.Where(x => !test1.Any(y => x.Contains(y)));