如果我有 2 个查询源,我如何找到一个不在另一个的查询源?
连接以在两者中查找项目的示例:
var results = from item1 in qs1.Items
join item2 in qs2 on item1.field1 equals item2.field2
select item1;
那么 linq 代码将返回 qs1 中不在 qs2 中的项目是什么?
来自马可·鲁索
NorthwindDataContext dc = new NorthwindDataContext();
dc.Log = Console.Out;
var query =
from c in dc.Customers
where !(from o in dc.Orders
select o.CustomerID)
.Contains(c.CustomerID)
select c;
foreach (var c in query) Console.WriteLine( c );
使用 except 扩展方法。
var items1 = new List<string> { "Apple","Orange","Banana" };
var items2 = new List<string> { "Grapes","Apple","Kiwi" };
var excluded = items1.Except(items2);
达伦·科普的回答:
var excluded = items1.Except(items2);
从性能的角度来看是最好的解决方案。
(注意:这对于至少常规 LINQ 来说是正确的,也许 LINQ to SQL 会根据Marco Russo 的博客文章改变事情。但是,我想在“最坏的情况下” Darren Kopp 的方法至少会返回 Russo 方法的速度,甚至在 LINQ to SQL 环境中)。
作为一个简单的例子,在LINQPad中试试这个:
void Main()
{
Random rand = new Random();
int n = 100000;
var randomSeq = Enumerable.Repeat(0, n).Select(i => rand.Next());
var randomFilter = Enumerable.Repeat(0, n).Select(i => rand.Next());
/* Method 1: Bramha Ghosh's/Marco Russo's method */
(from el1 in randomSeq where !(from el2 in randomFilter select el2).Contains(el1) select el1).Dump("Result");
/* Method 2: Darren Kopp's method */
randomSeq.Except(randomFilter).Dump("Result");
}
尝试一次注释掉这两种方法中的一种,并尝试不同 n 值的性能。
我的经验(在我的 Core 2 Duo 笔记本电脑上)似乎表明:
n = 100. Method 1 takes about 0.05 seconds, Method 2 takes about 0.05 seconds
n = 1,000. Method 1 takes about 0.6 seconds, Method 2 takes about 0.4 seconds
n = 10,000. Method 1 takes about 2.5 seconds, Method 2 takes about 0.425 seconds
n = 100,000. Method 1 takes about 20 seconds, Method 2 takes about 0.45 seconds
n = 1,000,000. Method 1 takes about 3 minutes 25 seconds, Method 2 takes about 1.3 seconds
方法 2(Darren Kopp 的回答)显然更快。
对于较大的 n,方法 2 的速度下降很可能是由于创建了随机数据(请随意放入 DateTime 差异来确认这一点),而方法 1 显然存在算法复杂性问题(只需查看即可看到)对于第一个集合中的每个数字,它至少是 O(N^2),它与整个第二个集合进行比较)。
结论:使用 Darren Kopp 对 LINQ 的“除外”方法的回答
另一种完全不同的看待它的方式是将 lambda 表达式(用于填充第二个集合的条件)作为谓词传递给第一个集合。
我知道这不是问题的确切答案。我认为其他用户已经给出了正确的答案。
这是同一件事的更简单版本,您不需要嵌套查询:
List<string> items1 = new List<string>();
items1.Add("cake");
items1.Add("cookie");
items1.Add("pizza");
List<string> items2 = new List<string>();
items2.Add("pasta");
items2.Add("pizza");
var results = from item in items1
where items2.Contains(item)
select item;
foreach (var item in results)
Console.WriteLine(item); //Prints 'pizza'