2012-02-29 39 views
5

Tôi có lớp myItem với 3 thuộc tính như sau:LINQ: Nhóm By và chọn từ một danh sách các đối tượng dựa trên giá trị max

class MyItem 
{ 
    private string _name; 
    private int _value 
    private DateTime _TimeStamp; 

    public MyItem(string name, int value, string timeStamp) 
    { 
     this._name = name; 
     this._value = value; 
     this._timeStamp = DateTime.Parse(timeStamp); 
    } 

    public string Name 
    { get {return this_name; } } 

    public int Value 
    { get {return this._value; } } 

    public DateTime TimeStamp 
    { get {return this._timeStamp; } } 

    // ... 
} 

tôi cũng có một danh sách myItem như sau:

var myItems = new List<MyItem>() { 
    new MyItem("A", 123, "23/02/2012"), 
    new MyItem("A", 323, "22/02/2012"), 
    new MyItem("B", 432, "23/02/2012"), 
    new MyItem("B", 356, "22/02/2012"), 
    // ... 
} 

làm cách nào tôi có thể GROUP BY myList để tôi CHỈ còn lại với các mục có TimeStamp Tối đa? tức là kết quả bên dưới:

"A" 123 23/02/2012<br> 

"B" 432 23/02/2012<br> 

Xin cảm ơn trước.

+0

Tôi đã tự do chỉnh sửa mã của bạn, tôi hy vọng tôi đã không làm sai ví dụ của bạn – BlackBear

Trả lời

6
myItems.GroupBy(item => item.Name) 
     .Select(grp => grp.Aggregate((max, cur) => 
          (max == null || cur.Date > max.Date) ? cur : max)) 

này sẽ chọn kết quả của bạn trong thời gian nhanh nhất có thể (ít nhất mà tôi có thể hình dung) mà không cần tạo đối tượng mới và lặp lại qua thu thập số lần ít nhất.

+0

Chính xác những gì tôi cần. Trong các bản ghi thậm chí tôi đã lấy từ cơ sở dữ liệu có ngày phù hợp và các giá trị khác nhau, tôi muốn lấy giá trị cao nhất. Bạn đá người đàn ông nhờ. –

0
var tmp = select i from myItems 
group i by i.Name into g 
select new MyItem 
{ 
    g.Name, 
    Value = g.OrderByDescending(x => x.Timestamp).First().Value, 
    Timestamp = g.Max(x => x.Timestamp) 
}; 
+0

điều này không biên dịch giao phối. – MaYaN

+0

Tôi đã quên "thành g". Bạn cần phải học LINQ nếu bạn muốn sử dụng, giao phối. –

3

Chọn Max từ Tập đoàn:

from item in MyItems 
group item by item.Name into grouped 
let maxTimeStamp = grouped.Max(i => i.TimeStamp) 
select grouped.First(i => i.TimeStamp == maxTimeStamp) 
+0

@ ALIR.Bousari - Bạn đã đúng. Câu lệnh select của truy vấn đang tạo một * new * 'MyItem' và sử dụng một [object initializer] (http://msdn.microsoft.com/en-us/library/bb397680.aspx) để thiết lập các thuộc tính. –

+0

@ChristopherCurrens - tnx để làm rõ tuy nhiên như bạn có thể thấy từ chỉnh sửa gần đây của tôi ở trên, tài sản của tôi là getters chỉ vì vậy không thể đặt chúng ở đây và tôi thực sự không muốn tạo đối tượng mới. – MaYaN

+0

@ ALIR.Bousari - Tôi hiểu rồi. Vâng, sau đó tôi sẽ lấy lại câu trả lời của tôi. Nó phức tạp hơn so với những lý do tại sao tôi đã xóa nó, nhưng nó không tạo ra các đối tượng mới. –

1
var temp = myItems.Where(x => x.TimeStamp == myItems.Where(y => y.Name == x.Name).Max(z => z.TimeStamp)).Distinct().ToList(); 
+0

Tuyệt vời! chỉ là những gì tôi muốn. cảm ơn bạn rất nhiều :-) – MaYaN

+1

@ ALIR.Bousari - Trong khi câu trả lời này tạo ra kết quả bạn mong đợi, nó là một thuật toán * rất * chậm: O (n^2). Tôi so sánh tốc độ thực hiện với câu trả lời của @ JoeTuskan với câu trả lời này, với * chỉ * 1000 mục trong danh sách thực hiện truy vấn 5 lần. Câu trả lời này lấy '00: 00: 15.8860736' trong khi Joe chỉ lấy' 00: 00: 00.0080155'. –

+0

@ Christopher, cảm ơn bạn đã phân tích điều này chắc chắn sẽ tác động khi danh sách lớn hơn (trường hợp của tôi), tôi không thể thực hiện giải pháp của Joe vì tôi không thể hiểu được phần CHỌN – MaYaN

0

OK, tôi đã thay đổi lớp học của bạn MyItem đối với một số tiện LINQ (hy vọng điều này không gây ra vấn đề) bằng cách thêm một constructor trống để các lớp:

public MyItem() { }

Trong một chương trình giao diện điều khiển mẫu , mã này sẽ hoạt động:

static void Main(string[] args) 
{ 
    var myItems = new List<MyItem>() 
    { 
     new MyItem("A", 123, "23/02/2012"), 
     new MyItem("A", 323, "22/02/2012"), 
     new MyItem("B", 432, "23/02/2012"), 
     new MyItem("B", 356, "22/02/2012") 
     // ... 
    }; 

    var grouped = from m in myItems 
        group m by m.Name into g 
        let maxTimestamp = g.Max(t => t.TimeStamp) 
        select new MyItem 
        { 
         Name = g.Key, 
         Value = g.First(f => f.TimeStamp == maxTimestamp).Value, 
         TimeStamp = maxTimestamp 
        }; 
    foreach (var gItem in grouped) 
    { 
     Console.WriteLine(gItem.Name + ", " + gItem.Value + ", " + gItem.TimeStamp); 
    } 

    Console.ReadLine(); 
} 

Kết quả phù hợp với kết quả mong đợi của bạn.

Các vấn đề liên quan