記事「Javaにおける入力した5個の数字の内、最大値と最小値を求める」を読んで
Java の Stream でやってみようと思ったが、
reduce の使い方が分からなさすぎて挫折。
Kotlin で復讐することにした。
/**
* シーケンスの最小値と最大値を返す。
*
* @param T シーケンスの要素の型。
* @return シーケンスの最小値と最大値。シーケンスが空の場合は `null`。
*/
fun <T : Comparable<T>> Sequence<T>.minAndMax(): MinAndMax<T>? {
// 拡張関数 `fold` 関数を使ってシーケンスの要素を1つの `MinAndMax` オブジェクトにまとめる。
return fold(
// 初期値は `null` とする。要素が1つもなければ結果は初期値のまま `null` となる。
null as MinAndMax<T>?
) { minAndMax, element ->
minAndMax
// 最小値と最大値を更新する。
?.let {
MinAndMax(
minOf(minAndMax.min, element),
maxOf(minAndMax.max, element)
)
}
// `minAndMax` が `null` の場合、
// 現在処理中の要素が1つめの要素ということになるため、
// その値が最小値で有り最大値となる。
?: MinAndMax(element, element)
}
}
/**
* 最小値と最大値を保持するオブジェクト。
*/
data class MinAndMax<T : Comparable<T>>(
val min: T,
val max: T
)
使用例。
import kotlin.random.Random
fun main() {
// 0以上100未満のランダムな整数を要素として持つシーケンスを生成する。
generateSequence {
// 0以上100未満のランダムな整数を生成する。
Random.nextInt(100)
}
// 10要素だけを持つシーケンスにする。
.take(10)
// シーケンスの要素を標準出力する。
.onEach { println("$it") }
// シーケンスの要素の最小値と最大値を求める。
.minAndMax()
// 最小値と最大値が求まった(`minAndMax()` の返値が `null` でなかった、シーケンスが空でなかった)場合、
// シーケンスの要素の最小値と最大値を標準出力する。
?.also { println("min: ${it.min}, max: ${it.max}") }
// 求まらなかった場合、シーケンスが空であった旨を標準出力する。
?: println("Empty sequence.")
}
出力例。
34
99
24
73
7
82
98
58
19
87
min: 7, max: 99
なお、分解宣言は意図的に使わなかった。
慣れない人には分かりにくいため。