コレクション内の最小値・最大値の取得
データの分析や処理において、「リストの中で最も高い数値」や「最も古い日付」を取得する操作は頻繁に行われます。
C#のLINQ(Language Integrated Query)が提供するMinおよびMaxメソッドを使用すると、単純な数値のリストだけでなく、オブジェクトの特定のプロパティや、計算式に基づいた最小値・最大値を簡潔に取得できます。
この記事では、MinとMaxの基本的な使い方から、ラムダ式を用いた応用的な値の算出方法までを解説します。
1. 単純な数値リストの最小・最大
intやdoubleなどの数値型のコレクションに対して、引数なしでMin()またはMax()を呼び出すと、そのコレクション内の最小値または最大値が返されます。
コード例:気温データの解析
using System;
using System.Linq; // LINQを使用するために必須
public class MinMaxBasicExample
{
public static void Main()
{
// 1週間の最高気温データ
double[] temperatures = { 24.5, 28.2, 22.0, 26.5, 30.1, 25.8, 23.4 };
// 最小値 (Min) と 最大値 (Max) を取得
double minTemp = temperatures.Min();
double maxTemp = temperatures.Max();
Console.WriteLine($"最低気温: {minTemp}℃");
Console.WriteLine($"最高気温: {maxTemp}℃");
}
}
出力結果:
最低気温: 22℃
最高気温: 30.1℃
2. オブジェクトの特定プロパティの最小・最大
オブジェクトのリストを扱う場合、引数にラムダ式 x => x.Property を指定することで、「どの値を基準にするか」を定義できます。
コード例:商品価格の調査
商品リストの中から、最も安い価格と最も高い価格を調べます。
using System;
using System.Collections.Generic;
using System.Linq;
// 商品クラス
public class ProductItem
{
public string Name { get; set; }
public int Price { get; set; }
}
public class MinMaxPropertyExample
{
public static void Main()
{
var products = new List<ProductItem>
{
new ProductItem { Name = "USB Cable", Price = 800 },
new ProductItem { Name = "Monitor", Price = 25000 },
new ProductItem { Name = "Mouse", Price = 4500 },
new ProductItem { Name = "Keyboard", Price = 12000 }
};
// Price プロパティを対象にする
int minPrice = products.Min(p => p.Price);
int maxPrice = products.Max(p => p.Price);
Console.WriteLine($"最安値: {minPrice}円");
Console.WriteLine($"最高値: {maxPrice}円");
}
}
出力結果:
最安値: 800円
最高値: 25,000円
この方法では、返されるのはあくまで「価格(int)」であり、商品オブジェクト(ProductItem)そのものではない点に注意が必要です。
(補足: .NET 6以降で、価格が最大となる商品オブジェクト自体を取得したい場合は、MaxByメソッドが利用できます。)
3. 計算式を用いた最小・最大
MinやMaxの引数(ラムダ式)には、単純なプロパティだけでなく、計算式を記述することも可能です。これにより、「単価 × 数量」や「面積」などの計算結果に基づいた最大・最小値を直接求めることができます。
コード例:長方形の面積比較
幅と高さを持つ長方形のデータから、最小の面積と最大の面積を計算します。
using System;
using System.Collections.Generic;
using System.Linq;
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
public class MinMaxCalculationExample
{
public static void Main()
{
var shapes = new List<Rectangle>
{
new Rectangle { Width = 10, Height = 10 }, // 面積 100
new Rectangle { Width = 5, Height = 8 }, // 面積 40
new Rectangle { Width = 20, Height = 10 }, // 面積 200
new Rectangle { Width = 8, Height = 8 } // 面積 64
};
// 面積 (幅 * 高さ) の最小値と最大値を計算して取得
double minArea = shapes.Min(r => r.Width * r.Height);
double maxArea = shapes.Max(r => r.Width * r.Height);
Console.WriteLine($"最小面積: {minArea}");
Console.WriteLine($"最大面積: {maxArea}");
}
}
出力結果:
最小面積: 40
最大面積: 200
事前にSelectメソッドで計算を行ってからMaxを呼ぶのと同義ですが、MinやMaxの中で直接計算式を書くほうがコードが簡潔になります。
注意点:空のコレクション
コレクションが空(要素数が0)の場合、MinやMaxメソッドの挙動は対象の型によって異なります。
- 数値型(
int,doubleなど):InvalidOperationException例外がスローされます。 - null許容型(
int?,double?など):nullが返されます(例外は発生しません)。
データが空になる可能性がある場合は、事前に.Any()で要素の存在を確認するか、null許容型にキャストしてから使用するなどの対策が必要です。
var emptyList = new List<int>();
// 例外が発生する
// int max = emptyList.Max();
// null許容型にキャストすれば null が返る
int? safeMax = emptyList.Cast<int?>().Max(); // null
まとめ
LINQのMinとMaxは、データの範囲を把握するための基本的なメソッドです。
Min()/Max(): 単純な数値リストで使用します。Min(x => x.Prop): オブジェクトの特定の値を基準にします。Max(x => x.A * x.B): 計算式の結果を基準にします。
集計処理において、合計(Sum)や平均(Average)と並んで頻繁に使用される重要な機能です。
