LINQ Menggunakan Max () untuk memilih satu baris


95

Saya menggunakan LINQ pada IQuerable yang dikembalikan dari NHibernate dan saya perlu memilih baris dengan nilai maksimum di beberapa bidang.

Saya telah menyederhanakan sedikit yang saya pertahankan. Saya perlu memilih satu baris dari tabel saya dengan nilai maksimum dalam satu bidang.

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

Ini tidak benar, tetapi saya tidak dapat menentukan bentuk yang benar.

BTW, apa yang sebenarnya saya coba capai adalah kira-kira ini:

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();

Saya mulai dengan lambda di atas tetapi saya telah menggunakan LINQPad untuk mencoba dan mengerjakan sintaks untuk memilih Max ().

MEMPERBARUI

Menghapus GroupBy adalah kuncinya.

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 ada jawaban yang bagus cukup jauh dalam pertanyaan itu: stackoverflow.com/a/6330485/444244
Boggin

Ada yang jauh lebih baik dari itu ...
M.Babcock

Coba lihat jawabannya .
Sergey Brunov

@Serge Saya setuju bahwa morelinq akan menjadi yang terbaik, tetapi saya khawatir proyek ini memiliki hambatan untuk menambahkan perpustakaan baru.
Boggin

Jawaban:


232

Saya tidak mengerti mengapa Anda berkelompok di sini.

Coba ini:

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

Pendekatan alternatif yang tablehanya akan berulang sekali adalah ini:

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

Hal ini berguna jika tableadalah IEnumerable<T>yang tidak hadir dalam memori atau yang dihitung dengan cepat.


1
Saya mengeluarkan pengelompokan tersebut dan ternyata saya bisa membuatnya berfungsi: from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Boggin

1
Anda juga dapat menyusun sintaks lambda: table.First(x => x.Status == table.Max(x => x.Status))
Landon Poch

13
@LandonPoch: Itu bukan ide yang bagus, karena ini akan menghitung maksimum N kali dengan N menjadi jumlah item dalam table.
Daniel Hilgarth

2
@Daniel Hilgarth: Tangkapan bagus! Itu sebenarnya akan menghitung maks per setiap baris dalam tabel. Salahku.
Landon Poch

17

Anda juga bisa melakukan:

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

13

Anda dapat mengelompokkan berdasarkan status dan memilih baris dari grup terbesar:

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

Yang pertama First()mendapatkan grup pertama (kumpulan baris dengan status terbesar); yang kedua First()mendapat baris pertama dalam grup itu.
Jika status selalu unqiue, Anda bisa mengganti second First()dengan Single().


7

Mengatasi pertanyaan pertama, jika Anda perlu mengambil beberapa baris yang dikelompokkan berdasarkan kriteria tertentu dengan kolom lain dengan nilai maksimal Anda dapat melakukan sesuatu seperti ini:

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

Lebih dari satu contoh:

Mengikuti:

 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);

Sama dengan:

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

-1

Cukup dalam satu baris:

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

Perhatikan bahwa ada dua tindakan. tindakan bagian dalam untuk mencari nilai maksimal, tindakan bagian luar untuk mendapatkan objek yang diinginkan.


Metode ini dibahas dalam komentar untuk jawaban yang diterima di mana itu menunjukkan bahwa itu adalah ide yang buruk.
Boggin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.