LINQ query to find if items in a list are contained in another list

北战南征 提交于 2019-12-17 08:31:49

问题


I have the following code:

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

I need to remove anyone in test2 that has @bob.com or @tom.com.

What I have tried is this:

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

bContained1 = false but bContained2 = true. I would prefer not to loop through each list but instead use a Linq query to retrieve the data. bContained1 is the same condition for the Linq query that I have created below:

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

The query above works on an exact match but not partial matches.

I have looked at other queries but I can find a close comparison to this with Linq. Any ideas or anywhere you can point me to would be a great help.


回答1:


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



回答2:


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



回答3:


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

L1 and L2 are both List<T>




回答4:


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.




回答5:


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




回答6:


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




回答7:


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.




回答8:


I think this would be easiest one:

test1.ForEach(str => test2.RemoveAll(x=>x.Contains(str)));



回答9:


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


来源:https://stackoverflow.com/questions/12656582/linq-query-to-find-if-items-in-a-list-are-contained-in-another-list

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!