LINQ Max()を使用して単一の行を選択する


95

NHibernateから返されたIQueryableでLINQを使用しており、いくつかのフィールドで最大値を持つ行を選択する必要があります。

固執している部分を簡略化しました。テーブルから1つのフィールドの最大値を持つ1つの行を選択する必要があります。

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

これは正しくありませんが、正しいフォームを見つけることができません。

ところで、私が実際に達成しようとしているのはおおよそこれです:

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

私は上記のラムダから始めましたが、LINQPadを使用してMax()を選択するための構文を試してみました。

更新

GroupByを削除することが重要でした。

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。バブコックはその質問のかなり下に良い答えがありました:stackoverflow.com/a/6330485/444244
ボギン

それよりずっと良いものがあります...
M.バブコック

答えを見てください。
セルゲイブルーノフ

@Sergeは、私は同意morelinqが最善だろうが、私はこのプロジェクトが新しいライブラリを追加することに障害を持っているんです。
Boggin

回答:


230

なぜここにグループ化しているのかわかりません。

これを試して:

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

table1回だけ繰り返す代替アプローチは次のようになります。

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

場合に便利ですtableですIEnumerable<T>メモリ内に存在しないか、その場で計算されています。


1
私はグループを取り出し、それを機能させることができることがわかりました: from u in User_Accounts where u.Status == User_Accounts.Max(y => y.Status) select u
Boggin

1
ネストすることもできますラムダ構文: table.First(x => x.Status == table.Max(x => x.Status))
ランドンPOCH

13
@LandonPoch:これは、Nがの項目数である場合に最大N回を計算するため、良い考えではありませんtable
Daniel Hilgarth、2012

2
@ダニエルヒルガース:良いキャッチ!実際には、テーブルのすべての行の最大値を計算します。私の悪い。
Landon Poch


13

ステータスごとにグループ化し、最大のグループから行を選択できます。

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

最初First()は最初のグループ(最大のステータスを持つ行のセット)を取得します。2番目First()は、そのグループの最初の行を取得します。
ステータスが常にunqiueの場合は、2番目First()をに置き換えることができますSingle()


7

最初の質問に対処します。特定の基準でグループ化された複数の行を、最大値を持つ他の列で取得する必要がある場合は、次のようなことができます。

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

その他の例:

フォロー:

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

等しい:

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

-1

単に 1行で:

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

2つのアクションがあることに注意してください。内部アクションは最大値を見つけるためのもので、外部アクションは目的のオブジェクトを取得するためのものです。


この方法は、受け入れられた回答へのコメントで議論されており、悪い考えだと指摘されました。
Boggin 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.