2011-02-25 27 views
1

我有兩個疑問,我在第二個使用的第一個結果是這樣結合兩個簡單的相關LINQ查詢

var temp = (ObjectTable.Where(o => o.Category == "Y")); 
var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == temp.Max(x => x.Value))}); 

有沒有辦法將這些組合成一個查詢?

編輯: 我不能直接鏈接它們,因爲我在第二個查詢中使用temp.Max()。

+0

我不認爲有一種方法可以將它變成單個查詢。另外,可能沒有任何理由這麼做(你可以做的唯一事情就是在第一個數據加載時使用'IEnumerable'慢數據源加載'ToList')。 –

+0

當你需要他時,Jon Skeet在哪裏? –

回答

1

可以使用查詢語法在一個語句中使用let關鍵字執行此操作。它只評估一次「最大」,所以它就像三個單獨的陳述一樣,只有一行。

var anonymousObjList = from o in ObjectTable 
         where o.Category == "Y" 
         let max = ObjectTable.Max(m => m.Value) 
         select new { o, IsMax = (o.Value == max) }; 

這是我唯一使用查詢語法的時間。你不能使用方法語法來做到這一點!

編輯:ReSharper的建議

var anonymousObjList = ObjectTable.Where(o => o.Category == "Y") 
    .Select(o => new {o, max = ObjectTable.Max(m => m.Value)}) 
    .Select(@t => new {@t.o, IsMax = (@t.o.Value == @t.max)}); 

然而這並不是最佳選擇。第一個Select將爲ObjectTable中的每個項目投影max屬性 - 將爲每個項目評估Max函數。如果您使用查詢語法,則只會評估一次。

再次,你只能用查詢語法來做到這一點。我不是查詢語法的粉絲,但這使得它值得,而且是我使用它的唯一情況。 ReSharper錯了。

+0

太棒了! 我得到了'var anonymousObjList = ObjectTable.Where(o => o.Category ==「Y」)。Select(o => new {o,max = ObjectTable.Max(m => m.Value)})。 選擇(@t => new {@ t.o,IsMax =(@ t.o.Value == @ t.max)});'來自resharper的轉換。 –

+0

@StackOverflowException - 這並不壞,但仍不如使用查詢語法的效率。你正在爲'ObjectTable'中的每個對象消除'new {o,max = ObjectTable.Max(m => m.Value)}'。如果您使用查詢語法,則只評估一次。 –

5

爲什麼?這將是清楚(並更有效),使之三:

var temp = (ObjectTable.Where(o => o.Category == "Y")); 
int max = temp.Max(x => x.Value); 
var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == max)}); 
+0

我不想創建臨時集合。 –

+0

這裏我沒有看到temp變量的問題。由於延遲執行temp不會對性能產生任何負面影響,因此對每個匿名對象進行一次評估而不是一次評估會使其更快。 – saus

+0

+1 - 他是對的。通常會這樣寫這樣的東西。將某些字符串串起來完成你所要求的內容也許是可能的,但是結果並不會更高效,當然也不會比這更可讀。 –

1

可能是最straightfirward重構與溫度的值來代替「臨時」的所有實例。由於看來這個值是不可變的,重構應該是有效的(但醜陋的):

var anonymousObjList = ObjectTable.Where(o => o.Category == "Y") 
    .Select(o => new {o, IsMax = (o.Value == ObjectTable.Where(o => o.Category == "Y").Max(x => x.Value))}); 

正如已經指出的那樣,這個查詢確實擁有對原沒有優勢,因爲查詢使用遞延執行並能建立起來。我真的建議將查詢更加

var temp = (ObjectTable.Where(o => o.Category == "Y")); 
var maxValue = temp.Max(x => x.Value);  
var anonymousObjList = temp.Select(o => new {o, IsMax = (o.Value == maxValue)}); 

比原來的更好,因爲每次「最大」被稱爲導致整個數據集的另一次迭代。由於它在原始選擇中被調用,Max被調用了n次。這使得原來的O(n^2)!