はじめに:「最小値取得」は“いちばん小さい値を素早く見つける技”
業務システムでは、最大値と同じくらい「最小値」もよく使います。
最も安い商品価格
最も古い日付(最初の処理日)
最も少ない数量
最も短い対応時間
こうした「いちばん小さい値」を取り出す処理は、C# / LINQ の Min を使うととても簡単に書けます。
ここでは、初心者向けに
- 数値の最小値
- オブジェクトのプロパティの最小値
- 空コレクション・null との付き合い方
- GroupBy と組み合わせた「○○ごとの最小値」
を順番にかみ砕いて説明していきます。
基本:数値コレクションに対する Min
int の最小値を取得する
まずは一番シンプルな例です。
using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 5, 2, 9, 1, 3 };
int min = numbers.Min();
Console.WriteLine(min); // 1
C#Min() は「列の中でいちばん小さい値」を返します。
ここでの重要ポイントは、「Min は“値そのもの”を返す」ということです。
最大値と同じく、最小値を持つ“要素そのもの”ではなく、値だけが返ってきます。
double や decimal の最小値
var values = new List<double> { 1.2, 3.4, 0.8 };
double min = values.Min(); // 0.8
C#var prices = new List<decimal> { 100.5m, 80.0m, 120.0m };
decimal minPrice = prices.Min(); // 80.0
C#金額などは decimal を使うことが多いので、そのまま Min が使えます。
オブジェクトのプロパティ最小値:Min(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 minAmount = sales.Min(s => s.Amount);
Console.WriteLine(minAmount); // 2000
C#ここでの重要ポイントは、「Min(s => s.Amount) の中で“何を基準に最小値を取るか”を指定している」ことです。
日付の最小値(最古の日付)を取得する
public class EventLog
{
public DateTime OccurredAt { get; set; }
}
C#var logs = new List<EventLog>
{
new EventLog { OccurredAt = new DateTime(2026, 2, 12) },
new EventLog { OccurredAt = new DateTime(2026, 2, 10) },
new EventLog { OccurredAt = new DateTime(2026, 2, 11) },
};
DateTime earliest = logs.Min(x => x.OccurredAt);
Console.WriteLine(earliest); // 2026-02-10
C#DateTime も「小さいほうが古い日付」なので、Min で「最古」を取れます。
空コレクション・null との付き合い方
空コレクションに対する Min は例外になる
Min は「空のコレクション」に対して呼ぶと例外になります。
var empty = new List<int>();
int min = empty.Min(); // InvalidOperationException
C#「最小値」という概念は、要素が1つもないと定義できないためです。
ここでの重要ポイントは、「Min を呼ぶ前に Any() で“1件以上あるか”を確認する」ことです。
int? min = null;
if (numbers.Any())
{
min = numbers.Min();
}
C#null かもしれないコレクション
List<int>? numbers = GetNumbersOrNull();
C#この場合も、いきなり numbers.Min() と書くと NullReferenceException です。
int? min = null;
if (numbers != null && numbers.Any())
{
min = numbers.Min();
}
C#業務的に「データなしなら 0 扱い」などのルールがある場合は、?? 0 を使います。
null 許容型(int? など)の最小値
public class Score
{
public string Name { get; set; } = "";
public int? Value { get; set; }
}
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? minScore = scores.Min(x => x.Value);
Console.WriteLine(minScore); // 80
C#null は無視され、80 と 95 の最小値で 80 になります。
全件 null の場合は、結果も null です。
ここでの重要ポイントは、「int? の Min は戻り値も int? になる」ことです。
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 minByCustomer = orders
.GroupBy(o => o.Customer)
.Select(g => new
{
Customer = g.Key,
MinAmount = g.Min(x => x.Amount)
});
C#ここでの重要ポイントは、「g.Min(…) は“そのグループの中だけ”の最小値を計算する」ことです。
日付ごとの最小金額
public class SaleWithDate
{
public DateTime Date { get; set; }
public int Amount { get; set; }
}
C#var dailyMin = salesWithDate
.GroupBy(s => s.Date.Date)
.Select(g => new
{
Date = g.Key,
MinAmount = g.Min(x => x.Amount)
})
.OrderBy(x => x.Date);
C#「最小値を持つ要素そのもの」が欲しいとき
Min は“値”しか返さない
「最小値を持つレコードそのもの」が欲しい場合は、Min ではなく並び替えを使います。
OrderBy + FirstOrDefault で取る
var minSale = sales
.OrderBy(s => s.Amount)
.FirstOrDefault();
C#金額の小さい順に並べ、先頭(=最小金額の明細)を取っています。
ここでの重要ポイントは、「Min は値、OrderBy + FirstOrDefault は要素そのもの」という使い分けです。
実務で意識してほしいこと
「何の最小値か」を変数名で明確にする
min だけだと意味が分かりません。
int minAmount = sales.Min(s => s.Amount);
DateTime earliest = logs.Min(x => x.OccurredAt);
C#こうするだけで、コードの意図が一気に読みやすくなります。
最小値取得の前に「フィルタ → グルーピング」の順番を意識する
例えば「2026年2月の最小金額」を出したいなら、
int minFebAmount = sales
.Where(s => s.Date.Year == 2026 && s.Date.Month == 2)
.Min(s => s.Amount);
C#「対象を絞ってから最小値を取る」という順番が大切です。
まとめ:「最小値取得ユーティリティ」は“いちばん小さい数字を素早く見つけるレーダー”
最小値取得の本質は、
「たくさんの明細の中から、“いちばん小さいもの”を素早く特定する」
ということです。
押さえておきたいポイントは、
- 数値は
Min()、オブジェクトはMin(x => x.プロパティ) - 空コレクションは例外になるので
Any()でチェック - null 許容型の Min は null を無視し、戻り値も null
- 「○○ごとの最小値」は
GroupBy→g.Min(...) - 要素そのものが欲しいときは
OrderBy + FirstOrDefault
このあたりが自然に書けるようになると、
“業務でよくある最小値取得”を LINQ でスマートに扱えるようになります。
