はじめに:「最大値取得」は“いちばん大きいものを一瞬で見つける技”
業務システムでは、よくこういう問いが出てきます。
「今日の売上の最大金額は?」
「この顧客の最新購入日は?」
「この一覧の中で、いちばん大きい値はどれ?」
こういう「いちばん大きいもの」を取ってくるのが「最大値取得」です。
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 の最大値
double や decimal に対しても同じです。
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 になり得る
「○○ごとの最大値」は GroupBy → g.Max(...) の流れで書く
「最大値を持つ要素そのもの」が欲しいときは OrderByDescending + FirstOrDefault を使う
このあたりが自然に書けるようになると、
「for で回して if で最大値を更新する」コードから卒業して、
“業務・実務で通用する LINQ ベースの最大値取得”を、落ち着いて書けるようになります。
