C# Tips | コレクション・LINQ:最大値取得

C# C#
スポンサーリンク

はじめに:「最大値取得」は“いちばん大きいものを一瞬で見つける技”

業務システムでは、よくこういう問いが出てきます。

「今日の売上の最大金額は?」
「この顧客の最新購入日は?」
「この一覧の中で、いちばん大きい値はどれ?」

こういう「いちばん大きいもの」を取ってくるのが「最大値取得」です。
C# / LINQ では Max を使うことで、for 文を書かずに一発で書けます。

ここから、初心者向けに

数値の最大値
オブジェクトのプロパティの最大値
空コレクション・null との付き合い方
GroupBy と組み合わせた「○○ごとの最大値」

を順番にかみ砕いて説明していきます。


基本:数値コレクションに対する Max

int の最大値を取得する

まずは一番シンプルな例です。

using System;
using System.Collections.Generic;
using System.Linq;

var numbers = new List<int> { 3, 10, 5, 7 };

int max = numbers.Max();

Console.WriteLine(max); // 10
C#

Max() は、「列の中でいちばん大きい値」を返します。
内部的には「最初の要素を暫定最大値として覚え、残りと順番に比較していく」という処理をしていますが、それを全部隠してくれています。

ここでの重要ポイントは、「Max は“値そのもの”を返す」ということです。
「最大値を持つ要素そのもの(オブジェクト)」ではなく、「最大の値」だけが返ってきます。

double や decimal の最大値

doubledecimal に対しても同じです。

var values = new List<double> { 1.2, 3.4, 2.5 };

double max = values.Max(); // 3.4
C#
var prices = new List<decimal> { 100.5m, 200.0m, 150.0m };

decimal maxPrice = prices.Max(); // 200.0
C#

金額などは decimal を使うことが多いので、Max もそのまま使えます。


オブジェクトのプロパティ最大値:Max(selector)

売上明細の「最大金額」を取得する

業務では、単純な数値のリストよりも、
「オブジェクトの中の特定のプロパティの最大値」を知りたいことが多いです。

売上明細クラスを用意します。

public class Sale
{
    public string Item { get; set; } = "";
    public int Quantity { get; set; }
    public int UnitPrice { get; set; }

    public int Amount => Quantity * UnitPrice;
}
C#

データを作ります。

var sales = new List<Sale>
{
    new Sale { Item = "A", Quantity = 2, UnitPrice = 1000 }, // 2000
    new Sale { Item = "B", Quantity = 1, UnitPrice = 5000 }, // 5000
    new Sale { Item = "C", Quantity = 3, UnitPrice = 1500 }, // 4500
};
C#

金額の最大値を取得します。

int maxAmount = sales.Max(s => s.Amount);

Console.WriteLine(maxAmount); // 5000
C#

ここでの重要ポイントは、「Max(s => s.Amount) の中で“何を基準に最大値を取るか”を指定している」ことです。
Max() は「そのまま最大値」、
Max(x => x.プロパティ) は「プロパティを取り出してから、その最大値」というイメージです。

日付の最大値(最新日付)を取得する

「最新日付」を取りたいときも、Max がそのまま使えます。

public class EventLog
{
    public DateTime OccurredAt { get; set; }
    public string Message { get; set; } = "";
}
C#
var logs = new List<EventLog>
{
    new EventLog { OccurredAt = new DateTime(2026, 2, 10), Message = "A" },
    new EventLog { OccurredAt = new DateTime(2026, 2, 12), Message = "B" },
    new EventLog { OccurredAt = new DateTime(2026, 2, 11), Message = "C" },
};

DateTime latest = logs.Max(x => x.OccurredAt);

Console.WriteLine(latest); // 2026-02-12
C#

DateTime も「大きいほうが新しい日付」なので、Max で「最新」を取れます。


空コレクション・null との付き合い方

空コレクションに対する Max は例外になる

Average と同じく、Max も「空のコレクション」に対して呼ぶと例外になります。

var empty = new List<int>();

int max = empty.Max(); // InvalidOperationException
C#

「最大値」という概念は、要素が1つもないと定義できないからです。

ここでの重要ポイントは、「Max を呼ぶ前に“1件以上あるか”を確認する」ことです。

int? max = null;

if (numbers.Any())
{
    max = numbers.Max();
}
C#

「データがあるときだけ最大値を計算し、ないときは null にしておく」という設計がよく使われます。

null かもしれないコレクション

コレクション自体が null のこともあります。

List<int>? numbers = GetNumbersOrNull();
C#

この場合も、いきなり numbers.Max() と書くと NullReferenceException です。

int? max = null;

if (numbers != null && numbers.Any())
{
    max = numbers.Max();
}
C#

「null =データなし」とみなすなら、null のままにしておくか、
業務的に「データなしなら 0 扱い」などのルールを決めておきます。

null 許容型(int? など)の最大値

int? の最大値も取れます。

public class Score
{
    public string Name { get; set; } = "";
    public int? Value { get; set; } // null のこともある
}
C#
var scores = new List<Score>
{
    new Score { Name = "A", Value = 80 },
    new Score { Name = "B", Value = null },
    new Score { Name = "C", Value = 95 },
};

int? maxScore = scores.Max(x => x.Value);

Console.WriteLine(maxScore); // 95
C#

null は無視され、80 と 95 の最大値で 95 になります。
全件 null の場合は、結果も null です。

ここでの重要ポイントは、「int? の Max は戻り値も int? になる」ことです。
「最大値が存在しない」状態を null で表現できます。


GroupBy と組み合わせて「○○ごとの最大値」を出す

顧客ごとの最大購入金額

グルーピングと最大値は、業務集計でよく組み合わされます。

public class Order
{
    public string Customer { get; set; } = "";
    public int Amount { get; set; }
}
C#
var orders = new List<Order>
{
    new Order { Customer = "A", Amount = 1000 },
    new Order { Customer = "A", Amount = 3000 },
    new Order { Customer = "B", Amount = 2000 },
};
C#

顧客ごとの最大購入金額を出します。

var maxByCustomer = orders
    .GroupBy(o => o.Customer)
    .Select(g => new
    {
        Customer = g.Key,
        MaxAmount = g.Max(x => x.Amount)
    });

foreach (var x in maxByCustomer)
{
    Console.WriteLine($"{x.Customer}: 最大 {x.MaxAmount} 円");
}
C#

ここでの重要ポイントは、「g.Max(...) は“そのグループの中だけ”の最大値を計算している」ことです。
GroupBy で「かたまり」を作り、その中で Max を使う、という流れです。

日付ごとの最大金額

日付単位の最大値もよくあります。

public class SaleWithDate
{
    public DateTime Date { get; set; }
    public int Amount { get; set; }
}
C#
var dailyMax = salesWithDate
    .GroupBy(s => s.Date.Date)
    .Select(g => new
    {
        Date     = g.Key,
        MaxAmount = g.Max(x => x.Amount)
    })
    .OrderBy(x => x.Date);
C#

「日付ごとの最大金額」を出し、日付順に並べています。


「最大値を持つ要素そのもの」が欲しいとき

Max は“値”しか返さない、という話

ここまで見てきたように、Max は「最大の値」を返します。
「最大金額を持つ売上明細そのもの」が欲しい場合は、少し工夫が必要です。

OrderByDescending + FirstOrDefault で取る

例えば、「金額が最大の売上明細」を1件取りたい場合。

var maxSale = sales
    .OrderByDescending(s => s.Amount)
    .FirstOrDefault();
C#

OrderByDescending で金額の大きい順に並べ、
FirstOrDefault で先頭(=最大金額の明細)を取っています。

ここでの重要ポイントは、「Max は“値”、OrderByDescending + FirstOrDefault は“要素そのもの”」という使い分けです。
「最大値だけでいいのか」「最大値を持つレコードが欲しいのか」で、書き方を変えます。


実務で意識してほしいこと

「何の最大値か」が分かる名前にする

max だけだと、「何の最大?」が分かりません。

maxAmount, maxPrice, maxDate, maxScore のように、
「何を基準にした最大値なのか」が分かる名前をつけてください。

int maxAmount   = sales.Max(s => s.Amount);
DateTime latest = logs.Max(x => x.OccurredAt);
C#

これだけで、コードの意図がかなり読みやすくなります。

最大値の前に「フィルタ」と「グルーピング」の順番を意識する

よくある流れは、

条件で絞る(Where)
必要ならグルーピングする(GroupBy)
最大値を取る(Max)

です。

例えば、「2026年2月の売上の最大金額」を出したいなら、

int maxFebAmount = sales
    .Where(s => s.Date.Year == 2026 && s.Date.Month == 2)
    .Max(s => s.Amount);
C#

のように、「まず対象を絞ってから最大値を取る」という順番を意識してください。


まとめ:「最大値取得ユーティリティ」は“いちばん強い数字を一瞬で見つけるレーダー”

最大値取得の本質は、
「たくさんの明細の中から、“いちばん大きいもの”を素早く特定する」ことです。

押さえておきたいポイントは、

数値コレクションは Max()、オブジェクトは Max(x => x.プロパティ)
空コレクションに対する Max は例外になるので、Any() などで 0 件をチェックする
null 許容型の最大値は null を無視し、戻り値も null になり得る
「○○ごとの最大値」は GroupByg.Max(...) の流れで書く
「最大値を持つ要素そのもの」が欲しいときは OrderByDescending + FirstOrDefault を使う

このあたりが自然に書けるようになると、
「for で回して if で最大値を更新する」コードから卒業して、
“業務・実務で通用する LINQ ベースの最大値取得”を、落ち着いて書けるようになります。

タイトルとURLをコピーしました