2012-02-02 22 views
67

Tôi đang sử dụng LINQ trên IQueryable được trả về từ NHibernate và tôi cần chọn hàng có (các) giá trị tối đa trong một vài trường.LINQ Sử dụng Max() để chọn một hàng đơn

Tôi đã đơn giản hóa bit mà tôi đang gắn bó. Tôi cần phải chọn một hàng từ bảng của tôi với giá trị tối đa trong một trường.

var table = new Table { new Row(id: 1, status: 10), new Row(id: 2, status: 20) } 

from u in table 
group u by 1 into g 
where u.Status == g.Max(u => u.Status) 
select u 

Điều này không chính xác nhưng tôi không thể làm đúng mẫu.

BTW, những gì tôi đang thực sự cố gắng để đạt xấp xỉ này:

var clientAddress = this.repository.GetAll() 
    .GroupBy(a => a) 
    .SelectMany(
      g => 
      g.Where(
       a => 
       a.Reference == clientReference && 
       a.Status == ClientStatus.Live && 
       a.AddressReference == g.Max(x => x.AddressReference) && 
       a.StartDate == g.Max(x => x.StartDate))) 
    .SingleOrDefault(); 

tôi bắt đầu với lambda trên nhưng tôi đã sử dụng LINQPad để thử và làm việc ra các cú pháp để lựa chọn Max ().

CẬP NHẬT

Loại bỏ các groupby là chìa khóa.

var all = this.repository.GetAll(); 

var address = all 
      .Where(
       a => 
       a.Reference == clientReference && 
       a.Status == ClientStatus.Live && 
       a.StartDate == all.Max(x => x.StartDate) && 
       a.AddressReference == all.Max(x => x.AddressReference)) 
      .SingleOrDefault(); 
+0

có thể trùng lặp: http://stackoverflow.com/questions/1101841/linq-how-to-perform-max-on-a-property-of-all-objects-in-a-collection-and-ret –

+0

@ M.Babcock có một câu trả lời tốt khá xa trong câu hỏi đó: http: // stackoverflow.com/a/6330485/444244 – Boggin

+0

Có nhiều cái tốt hơn thế ... –

Trả lời

166

Tôi không thấy lý do bạn nhóm vào đây.

Hãy thử điều này:

var maxValue = table.Max(x => x.Status) 
var result = table.First(x => x.Status == maxValue); 

Một cách tiếp cận thay thế đó sẽ lặp table chỉ một lần sẽ là:

var result = table.OrderByDescending(x => x.Status).First(); 

này là hữu ích nếu table là một IEnumerable<T> đó không phải là hiện tại trong bộ nhớ hoặc được tính toán khi đang bay.

+1

Tôi đã lấy nhóm và tìm thấy tôi có thể làm cho nó hoạt động: 'từ u trong User_Accounts nơi u.Status == User_Accounts.Max (y => y.Status) chọn u' – Boggin

+1

Bạn cũng có thể lồng cú pháp lambda: 'table.First (x => x.Status == table.Max (x => x.Status))' –

+10

@LandonPoch: Đó không phải là một ý tưởng hay, vì điều này sẽ tính toán N lần tối đa với N là số mục trong 'bảng'. –

11

Bạn có thể nhóm theo tình trạng và chọn một hàng từ nhóm lớn:

table.GroupBy(r => r.Status).OrderByDescending(g => g.Key).First().First(); 

Các First() đầu tiên được nhóm đầu tiên (tập hợp các hàng với tư cách lớn nhất); số thứ hai First() nhận hàng đầu tiên trong nhóm đó.
Nếu trạng thái luôn vô tình, bạn có thể thay thế số First() thứ hai bằng Single().

9

Bạn cũng có thể làm:

(from u in table 
orderby u.Status descending 
select u).Take(1); 
5

Phát biểu câu hỏi đầu tiên, nếu bạn cần phải thực hiện một số hàng được phân nhóm theo tiêu chí nhất định với các cột khác có giá trị tối đa bạn có thể làm một cái gì đó như thế này:

var query = 
    from u1 in table 
    join u2 in (
     from u in table 
     group u by u.GroupId into g 
     select new { GroupId = g.Key, MaxStatus = g.Max(x => x.Status) } 
    ) on new { u1.GroupId, u1.Status } equals new { u2.GroupId, Status = u2.MaxStatus} 
    select u1; 
-1

đơn giản chỉ cần trong một dòng:

var result = table.First(x => x.Status == table.Max(y => y.Status)); 

Lưu ý rằng có hai hành động. hành động bên trong là để tìm giá trị tối đa, hành động bên ngoài là để lấy đối tượng mong muốn.

+0

Phương pháp này đã được thảo luận trong phần nhận xét cho câu trả lời được chấp nhận, nơi nó được chỉ ra rằng đó là một ý tưởng tồi. – Boggin

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