クエリ ソースが 2 つある場合、一方にあり、他方にないものを見つけるにはどうすればよいですか?
両方の項目を検索する結合の例:
var results = from item1 in qs1.Items
join item2 in qs2 on item1.field1 equals item2.field2
select item1;
では、qs2 にはない qs1 のアイテムを返す linq コードは何でしょうか?
マルコ・ルッソより
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のブログ投稿に従って状況を変更します。ただし、「最悪の場合」では、DarrenKoppのメソッドは少なくとも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");
}
2つの方法のいずれかを一度にコメントアウトして、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には明らかにアルゴリズムの複雑さの問題があります(見ただけでわかります)。は、2番目のコレクション全体と比較している最初のコレクションの各数値に関して少なくともO(N ^ 2)です)。
結論: LINQの「Except」メソッドに対するDarrenKoppの回答を使用する
もう 1 つのまったく別の見方は、ラムダ式 (2 番目のコレクションに値を設定するための条件) を述語として最初のコレクションに渡すことです。
これが質問に対する正確な答えではないことはわかっています。他のユーザーがすでに正しい答えを出していると思います。
同じことのより単純なバージョンを次に示します。クエリをネストする必要はありません。
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'