linq-如何在一个查询源中查询不在另一个查询源中的项目?

时间:2020-03-05 18:49:39  来源:igfitidea点击:

如果我有2个查询源,如何找到一个不在另一个中的查询源?

结合查找两个项目的示例:

var results = from item1 in qs1.Items
   join item2 in qs2 on item1.field1 equals item2.field2
   select item1;

那么,linq代码将返回qs1中不在qs2中的项是什么?

解决方案

回答

从马可·鲁索(Marco Russo)

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

回答

这是同一件事的更简单版本,我们无需嵌套查询:

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'

回答

另一种完全不同的查看方式是将lambda表达式(填充第二个集合的条件)作为谓词传递给第一个集合。

我知道这不是问题的确切答案。我认为其他用户已经给出了正确的答案。

回答

达伦·科普(Darren Kopp)的答案:

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(达伦·科普的答案)显然更快。

对于较大的n,方法2的速度降低很可能是由于创建了随机数据(随意放入DateTime差异以确认这一点),而方法1显然存在算法复杂性问题(仅通过查看即可看到)对于第一个集合中的每个数字与整个第二个集合进行比较,至少为O(N ^ 2)。

结论:使用达伦·科普(Darren Kopp)对LINQ的"例外"方法的回答