集約オペレーション(aggregate)
Kotlinのコレクションは良く使われる集約(aggregate)オペレーションの関数を含んでいる。 集約オペレーションとは、コレクションの中身を元に単一の値を返すオペレーションの事です。 多くのものは良く知られていて、他のプログラム言語のものと同様に振る舞います:
minOrNull()とmaxOrNull()は最小と最大の要素をそれぞれ返す。空のコレクションに対して行うとnullを返す。average()は数値のコレクションの平均値を返す。sum()は数値のコレクションの合計を返す。count()コレクションの要素数を返す。
最小と最大の要素を、何らかのセレクタ関数やカスタムなComparatorを元にして返す関数もある:
maxByOrNull()とminByOrNull()はセレクタ関数を引数にとり、そのセレクタが返した値が最大の要素と最小の要素をそれぞれ返す。maxWithOrNull()とminWithOrNull()はComparatorオブジェクトを引数に取り、そのComparatorによる最大と最小の要素をそれぞれ返す。maxOfOrNull()とminOfOrNull()はセレクタ関数を引数に取り、セレクタが返した最大の値か最小の値をそれぞれ返す。maxOfWithOrNull()とminOfWithOrNull()はComparatorオブジェクトを引数に取り、セレクタの返した値をComparator基準で最大の値か最小の値を返す。(訳注:Comparatorとセレクタの2つの関数を引数に取る)
これらの関数は、空のコレクションに対してはnullを返す。
この挙動だけが違う代替バージョンもある。
maxOf、 minOf、 maxOfWith、 minOfWithなどです。
これらの関数はそれぞれの対応するものと同じ挙動をするけれど、空のコレクションに対してはNoSuchElementExceptionを投げます。
普通のsum()の他に、より高度なsum関数、sumOf()関数もあります。
これはセレクタ関数を引数に取り、それを全要素に適応した結果の合計を返します。
セレクタは異なる数値型を返しても構いません:Int, Long, Double, UInt, ULongなど (JVMの場合は BigInteger と BigDecimalもOK)。
foldとreduce
より特殊なケースのためには、reduce() と fold()関数があります。これは渡されたオペレーションをコレクションの要素に順番に適用していって、累積した結果を返します。
オペレーションは引数2つを取ります:前回までに累積した値と、コレクションの要素です。
reduceとfoldの違いは、fold()は初期値を引数に取り、それを最初のステップでの累積値として用いるのに対し、
reduce()は最初のステップとしては1つ目と2つ目の要素を引数に実行する所が違いです。
上の例は両者の違いを示しています: fold()を使って要素を二倍したものの合計を計算しています。
同じ関数をreduce()に渡すと、異なった結果を返します。
なぜならリストの最初と二番目の要素を最初のステップの引数にしますが、
そのため最初の要素が2倍されない為です。
逆順に関数を適用していきたければ、
reduceRight()とfoldRight()関数を使いましょう。
これらの関数はfold() と reduce() と似たように振る舞いますが、
最後の要素から始まって一つ前、その一つ前、と続いていく所が違います。
reduceRightとfoldRightはオペレーションの引数の順番が変わる事に注意してください: 1つ目の引数が要素で二つ目の引数が累積値となります。
要素のインデックスも引数に取るオペレーションを適用する事も出来ます。
この場合はreduceIndexed()
とfoldIndexed()関数を使います。
要素のインデックスはオペレーションには最初の引数として渡されます。
最後に、そのようなオペレーションを右から左に適用する関数もあります。reduceRightIndexed()
とfoldRightIndexed()です。
すべてのreduce系の関数は空のコレクションには例外を投げます。代わりにnullを受け取りたければ、それらの対応する*OrNull()バージョンを使ってください:
途中の累積値を保存したい場合は、
runningFold() (またはその省略名の scan())
とrunningReduce()関数があります。
オペレーションにインデックスのパラメータが必要な場合は、runningFoldIndexed()か
runningReduceIndexed()を使ってください。