2015-11-05 51 views
4

考慮以下代碼:LINQ - 列出最低價格只有

var items = (new[] { 
    new {itemTypeId = 1 , cost=100 }, 
    new {itemTypeId = 2 , cost=200 }, 
    new {itemTypeId = 1 , cost=50 }, 
    new {itemTypeId = 3 , cost=150 }, 
    new {itemTypeId = 1 , cost=75 } 
}); 

var o = items.OrderBy(x => x.cost) 
    .ToList() 
    .GroupBy(x => x.itemTypeId) 
    .Select(g => new { g, count = g.Count() }) 
    .SelectMany(t => t.g.Select(b => b).Zip(Enumerable.Range(1, t.count), (j, i) => new { j.itemTypeId , j.cost })); 

foreach (var i in o) 
{ 
    Console.WriteLine("{0} {1} ", i.itemTypeId, i.cost); 
} 

輸出:

1 | 50 
1 | 75 
1 | 100 
3 | 300 
2 | 200 

其實我希望它輸出:

1 | 50 
2 | 200 
3 | 300 

查詢應只返回的產品價格最低的某種類型。因此,在任何返回的數據中,應該只有每種商品類型中的一種,並按價格排序。

我以爲Enumerable.Range(1, t.count)在TSQL中做了一個類似於Row_number over的工作。個人看不出上面的代碼實際上實現了什麼,除非我寫了它完全錯誤。

有什麼建議嗎?

+2

哪裏300是從哪裏來的?它不應該是150嗎? –

回答

6

您可以通過itemTypeId必須組,然後由項目類型,它給你一個IGrouping<T>,從你一鍵搞定接受的最低通過訂購組由cost:

var o = items 
    .GroupBy(x => x.itemTypeId) 
    .Select(g => g.OrderBy(x => x.cost).First()) 
    .OrderBy(x => x.cost); 
+0

在我的真實世界的代碼中,我有一個.SelectMany從其他表中提取數據。關於如何將這與您的解決方案結合起來,我有點遺憾。我編輯了我的問題以顯示。對不起 - 我推動我的運氣! – ComfortablyNumb

+0

@ComfortablyNumb:也許你想問另一個問題。沒有樣本數據或表格如何關聯很難理解。如果它不是LINQ-To-Objects,那麼還應該提及LINQ提供程序。 –

+0

夠公平 - 會做。再次感謝 – ComfortablyNumb

7

集團和IEnumerable<T>的分組項目。然後你可以根據項目(Select),其爲匿名類型,在IGrouping<T>x使用Min獲得每組最低的成本:

+1

試圖學習linq的人,特別是聚合函數,從解釋中獲益匪淺。 –

+0

@AdamHouldsworth,當我意識到可能缺少一些'OrderBy'時,我正要添加一些解釋。謝謝。 – haim770

+0

沒問題。從技術上講,排序會給出所需的輸出,假設條目類型的順序(期望的輸出在所需順序上是不明確的,因爲它也是按最低成本排序),但我認爲混淆的主要來源是分組,你的回答解決了這個問題。 –