70

我有以下代码:

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

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

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

上面的查询适用于完全匹配但不是部分匹配。

我查看了其他查询,但我可以找到与 Linq 的密切比较。您可以指出我的任何想法或任何地方都会有很大帮助。

4

9 回答 9

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

根据 Tim 的建议,更快的版本:

var test2NotInTest1 = test2.Where(t2 => !test1.Any(t1 => t2.Contains(t1)));
于 2012-09-29T21:34:13.050 回答
20
bool doesL1ContainsL2 = l1.Intersect(l2).Count() == l2.Count;

L1 和 L2 都是List<T>

一个简单的解释是:如果两个迭代的结果交集的长度与较小列表的长度相同(此处为 L2),则所有元素必须在较大列表中(此处为 L1)

于 2017-08-03T08:12:27.887 回答
15
var output = emails.Where(e => domains.All(d => !e.EndsWith(d)));

或者,如果您愿意:

var output = emails.Where(e => !domains.Any(d => e.EndsWith(d)));
于 2012-09-29T21:39:25.560 回答
5

这里不需要像这样使用 Linq,因为已经有一个扩展方法可以为您执行此操作。

Enumerable.Except<TSource>

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

您只需要创建自己的比较器即可根据需要进行比较。

于 2012-09-29T21:32:22.467 回答
3

像这样的东西:

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)

现场示例:这里

于 2012-09-29T21:37:03.200 回答
2
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);

如果查询表单是您想要使用的,那么它是清晰易读的,并且或多或少是“高性能”的。

我的意思是你想要做的是一个 O(N*M) 算法,也就是说,你必须遍历 N 个项目并将它们与 M 个值进行比较。您想要的是只遍历第一个列表一次,并根据需要与另一个列表进行多次比较(最坏的情况是电子邮件有效,因为它必须与每个黑名单域进行比较)。

from t2 in test我们将电子邮件列表循环一次。

test1.Any(t => t2.Contains(t)) == false我们与黑名单进行比较,当我们找到一个匹配项时返回(因此,如果不需要,则不与整个列表进行比较)

select t2保留那些干净的。

所以这就是我会使用的。

于 2012-09-29T21:40:12.080 回答
0

尝试以下操作:

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;

这适用于提供的测试集(并且看起来正确)。

于 2012-09-29T21:34:19.967 回答
-3

I think this would be easiest one:

test1.ForEach(str => test2.RemoveAll(x=>x.Contains(str)));
于 2015-01-04T15:54:14.853 回答
-3
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());
于 2016-02-28T15:52:24.017 回答