2016-07-27 52 views
1

我是Joins的業餘愛好者,但我試圖使用表達式鏈接語法而不是LINQ語句。我發現的大多數例子都使用了數組或列表{Lists <class>};但沒有數組列表{名單<array>}在lambda表達式鏈接語法中加入列表<Array>

List<int[]> needHelp = new List<int[]>{ 
new int[3] { 10, 20, 50}, 
new int[3] { 10, 21, 53}, 
new int[3] { 10, 22, 55}, 
new int[3] { 11, 20, 60}, 
new int[3] { 11, 22, 51} }; 

List<int[]> ghosts = new List<int[]>{ 
new int[3] { 10, 45, 65}, 
new int[3] { 11, 34, 60} }; 

的LINQ「查詢」語法的工作原理是:

List<int[]> result = (from h in needHelp join g in ghosts on h[0] equals g[0] 
         where h[1] == 21 select g).ToList(); 

但這種「方法」表達鏈語法不是爲我工作:

List<int[]> result = needHelp.Join(ghosts, x=>x[0], y=>y[0], (x,y) => y).Where(x => x[1] == 21).ToList(); 

對於那些有興趣我已經發現,這lambda表達式鏈可以打印出陣列的列表,而無需使用兩個foreach循環。

result.ForEach(x => { Array.ForEach(x, e => Console.Write(e + " ")); Console.WriteLine();}); 

好吧,我想我找到了我自己的解決方案,它是通過改變where子句的位置。但是,在加入之前哪裏必須來到,而不是之後要去的原因是什麼?我在帖子上看到,如果這是一個數據庫調用where類在「.Join」之前,那麼它在服務器上而不是客戶端上處理。然後,我假設在連接之後嘗試使用它,這是剩餘數據的超出範圍,在這種情況下將是y(列表<int[]> ghosts)。

回答

1

Join s和Where s通常是不可互換的。

如果你讀了你的表情鏈「出聲」,它會讀這樣的:首先讓我在ghostsneedHelp東西匹配的第一元素,所有的陣列,然後從選擇那些有數組第二個元素等於21

因此,在Join之後的那一刻,您只剩下來自ghosts列表的數組。您的WHERE子句不會返回任何內容,因爲ghosts中沒有第二個元素等於21.您正在檢查needHelp列表中的內容。

我會建議你做交換JoinWhere

List<int[]> result = needHelp.Where(x => x[1] == 21).Join(ghosts, x=>x[0], y=>y[0], (x,y) => y).ToList(); 

如果它是混亂的爲你的來源,不要以爲在功能xy變量意味着什麼在多個功能。您的Where呼叫相關xneedHelp,但這並不意味着Join功能中的xneedHelp相關;它引用Where的輸出,它們是來自ghosts的元素。

+0

是的,這就是我認識到,返回關加入僅僅是Y(鬼),因此這裏來了之後就沒有結果。 另外我也明白,在lambda完全獨立於X的Join中,這是一個KeyPointer需要幫助。 – Edward

+0

這個答案對我有幫助,而且這個答案已經有超過一百個觀點,所以也許它幫助了其他人;希望如果有的話,未來的任何人都可以幫助你解決問題。如果您覺得這是一個很好的問題,我想要求您提出這個問題並進行徹底解釋。謝謝 – Edward

+0

您也可以將我的答案標記爲正確答案! –

0

您的加入方法不是您提供的查詢語法的翻譯。

(在加入x[1])上h[1]查詢過濾器,但你只能選擇yg在查詢中),所以凡適用於錯誤的事情後。

這是你查詢的直接翻譯:

List<int[]> result = 
    needHelp 
    .Join (ghosts, x => x[0], y => y[0], (x, y) => new { x, y }) 
    .Where (anon => anon.x[1] == 21) 
    .Select (anon => anon.y) 
    .ToList(); 
+0

您聲稱我的語法從LINQ查詢表達式到lambda鏈表達式不正確?你指出我認爲稱爲匿名輸入參數,查詢中的h也是一個別名。 至於你的加入lambda線,這就像我的,除了它返回列表這是好的,如果我正在尋找兩個,但在這種情況下,我只需要鬼列表。 – Edward

+0

@愛德華你需要兩個加入後;在你的查詢中,它與你在select子句中的where子句和g中使用h相同。這意味着兩者都是從聯合中選擇的(伊凡在他的回答中稱爲透明標識符)。如果你在我的「連鎖店」中看起來更仔細一些,我和你的查詢有相同的邏輯步驟:加入,然後篩選並最終投影;而他的這個投影我只保留那些來自幽靈的物品。如果不是這種情況,我又返回了一些東西,它不會編譯,因爲返回類型不正確 – Sehnsucht

0

的確切方法的語法相當於該查詢語法

from h in needHelp join g in ghosts on h[0] equals g[0] 
where h[1] == 21 
select g 

的是這樣的:

needHelp.Join(ghosts, h => h[0], g => g[0], (h, g) => new { h, g }) 
    .Where(x => x.h[1] == 21) 
    .Select(x => x.g); 

查詢語法使用所謂的「透明標識符」來隱藏這些中間匿名類型,並且這就是爲什麼對於涉及連接的查詢更可取。

談到連接和一般情況下,IMO總是在加入之前應用過濾器總是更好,尤其是在LINQ to Objects中,因爲數據庫查詢優化器無論如何都會重新排列過濾器和連接操作。因此,一個更好的查詢(從性能和內存分配)會是:

needHelp.Where(h => h[1] == 21).Join(ghosts, h => h[0], g => g[0], (h, g) => g); 
+0

這使得由於這個語句的作用,因爲你返回兩個列表,在那裏我只返回一個。 所以,如果你的意見是先放在哪裏,那麼爲什麼不把它納入你給的答案? – Edward

+1

完成。我最初並不是因爲我在想你只想爲你的查詢獲得等價的方法語法。作爲一般性建議,嘗試使用相同的變量名稱,以便輕鬆地將一種語法的各個部分與另一種語法的部分相關聯。這並不總是可能的,但至少應該接近。如果有多個連接(如果您還需要離開外部連接),則方法語法確實很痛苦。 –