LINQ Sử dụng Max () để chọn một hàng


95

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ị lớn nhất trong một vài trường.

Tôi đã đơn giản hóa một chút mà tôi đang bám vào. Tôi cần chọn một hàng từ bảng của mình với giá trị lớn nhất 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ể tìm ra biểu mẫu phù hợp.

BTW, những gì tôi thực sự đang cố gắng đạt được gần như thế 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 đang sử dụng LINQPad để thử và tìm ra cú pháp để chọn Max ().

CẬP NHẬT

Xóa 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();


@ M.Babcock đã có một câu trả lời khá hay cho câu hỏi đó: stackoverflow.com/a/6330485/444244
Boggin

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


@Serge Tôi đồng ý rằng morelinq sẽ là tốt nhất nhưng tôi e rằng dự án này cản trở việc thêm các thư viện mới.
Boggin

Câu trả lời:


230

Tôi không hiểu tại sao bạn lại nhóm ở đây.

Thử cái 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ế tablechỉ lặp lại một lần sẽ là:

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

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


1
Tôi đã tách nhóm ra và thấy rằng tôi có thể làm cho nó hoạt động: from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Boggin

1
Bạn cũng có thể tổ cú pháp lambda: table.First(x => x.Status == table.Max(x => x.Status))
Landon Poch

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

2
@Daniel Hilgarth: Bắt tốt! Trên thực tế, điều đó sẽ tính toán giá trị tối đa cho mỗi hàng trong bảng. Lỗi của tôi.
Landon Poch

17

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

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

13

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

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

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


7

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

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;

0

Thêm một ví dụ:

Theo:

 qryAux = (from q in qryAux where
            q.OrdSeq == (from pp in Sessao.Query<NameTable>() where pp.FieldPk
            == q.FieldPk select pp.OrdSeq).Max() select q);

Bằng:

 select t.*   from nametable t  where t.OrdSeq =
        (select max(t2.OrdSeq) from nametable t2 where t2.FieldPk= t.FieldPk)

-1

Đơn giản chỉ 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.


Phương pháp này đã được thảo luận trong các ý kiến ​​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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.