C#で複数の値の最大値・最小値を取得
Math クラスのMath.Max()
、Math.Min()
は2つの値しか比べられない。
任意の個数の複数の値から最大値、最小値を取得したい。こんな↓イメージ。
Max(0, 1, 2, 3, 4); // => 4
Min(0, 1, 2, 3, 4); // => 0
paramsで可変長引数
params キーワードを使用すると、可変個の引数を受け取るメソッド パラメーターを指定できます。
パラメーター宣言で指定した型の引数のコンマ区切りのリスト、または指定した型の引数の配列を渡すことができます。 また、引数を渡さないこともできます。 引数を渡さない場合、params リストの長さはゼロになります。 params (C# リファレンス)
引数が渡されない場合も考慮しておく必要がある。とりあえず0を返すようにしているが、ちゃんと例外処理したほうがよい。
public int Max(params int[] nums)
{
// 引数が渡されない場合
if(nums.Length == 0) return 0;
int max = nums[0];
for(int i = 1; i < nums.Length; i++)
{
max = max > nums[i] ? max : nums[i];
// Minの場合は不等号を逆にすればOK
}
return max;
}
引数として配列も渡せる。
Max(0, 1, 2, 3, 4); // => 4
int[] numbers = {0, 1, 2, 3, 4};
Max(numbers); // => 4
ジェネリック
int
やdouble
などの型ごとにメソッドをつくるのは面倒なので、ジェネリックで複数の型に対応させる。
public T Max<T>(params T[] nums) where T : IComparable
{
if(nums.Length == 0) return default(T);
T max = nums[0];
for(int i = 1; i < nums.Length; i++)
{
max = max.CompareTo(nums[i]) > 0 ? max : nums[i];
// Minの場合は不等号を逆にすればOK
}
return max;
}
メソッドを呼び出すときは型引数を使用するが、省略することも出来る。省略された型引数はコンパイラが推論する。
Max<int>(0, 1, 2, 3, 4); // => 4
Max<double>(0.0, 0.1, 0.2, 0.3, 0.4); // => 0.4
Max(0, 1, 2, 3, 4); // => 4
Max(0.0, 0.1, 0.2, 0.3, 0.4); // => 0.4
whereとIComparable
今回は引数同士を比較するので、使用される型を比較が可能な型に限定する必要がある。where T : IComparable
の部分で型に制約をもたせている。
ジェネリック型定義では、where 句は、ジェネリック宣言で定義されている型パラメーターの引数として使用できる型に対する制約を指定します。 where (ジェネリック型制約) (C# リファレンス)
インスタンスの並べ替えのために値の型またはクラスで実装する、汎用の、型固有の比較メソッドを定義します。 IComparable インターフェイス (System)
IComparable
型はCompareTo
メソッドを持っており、これを利用して値の比較を行う。
現在のインスタンスを同じ型の別のオブジェクトと比較し、現在のインスタンスの並べ替え順序での位置が、比較対象のオブジェクトと比べて前か、後か、または同じかを示す整数を返します。 IComparable.CompareTo メソッド (System)
instance.CompareTo(object)
の戻り値と比較結果は以下のようになる。
戻り値 | 比較結果 |
---|---|
0より小さい値 | instance < object |
0 | instance = object |
0より大きい値 | instance > object |
default(T)
このキーワードは、参照型の場合には null を返し、数値の値型にはゼロを返します。 構造体の場合、ゼロまたは null (値型か参照型かによって変わります) に初期化された構造体の各メンバーを返します。 ジェネリック コードの default キーワード (C# プログラミング ガイド)
規定値を指定したい場合に用いる。
注意点
params
使用時は引数0個も許されているが、同時にジェネリックも使う場合、型引数を省略して引数0個だとエラーになる。
Max<int>(); // => 0 (default(int))
Max(); // => error
CS1501
のエラーが出る。
$ error CS1501: No overload for method `Max' takes `0' arguments