web-dev-qa-db-ja.com

Kotlinのfoldとreduceの基本的な違いは何ですか?どちらを使用するか?

私はKotlinの基本を調べていますが、Kotlinのfold()とreduce()の両方の関数とかなり混同していますが、両方を区別する具体的な例を教えてもらえますか?

77
TapanHP

fold は初期値を取り、渡されたラムダの最初の呼び出しはその初期値とコレクションの最初の要素をパラメーターとして受け取ります。

たとえば、整数のリストの合計を計算する次のコードを使用します。

listOf(1, 2, 3).fold(0) { sum, element -> sum + element }

ラムダの最初の呼び出しは、パラメータ0および1を使用します。

初期値を渡す機能は、操作に何らかのデフォルト値またはパラメーターを提供する必要がある場合に役立ちます。たとえば、リスト内で最大値を探していて、何らかの理由で少なくとも10を返したい場合、次のようにできます。

listOf(1, 6, 4).fold(10) { max, element ->
    if (element > max) element else max
}

reduce は初期値を取りませんが、代わりにアキュムレーターとしてコレクションの最初の要素から始まります(次の例ではsumと呼ばれます)。

たとえば、整数の合計をもう一度行いましょう。

listOf(1, 2, 3).reduce { sum, element -> sum + element }

ここでのラムダの最初の呼び出しは、パラメータ1および2を使用します。

操作が適用先のコレクションの値以外の値に操作が依存していない場合は、reduceを使用できます。

168
zsmb13

私が呼び出す主な機能の違い(他の答えのコメントに記載されていますが、理解するのは難しいかもしれません)は、空のコレクションで実行された場合、reduce例外をスローしますです。

listOf<Int>().reduce { x, y -> x + y }
// Java.lang.UnsupportedOperationException: Empty collection can't be reduced.

これは、.reduceが「データなし」のイベントで返す値を知らないためです。

これを.foldと比較すると、「開始値」を指定する必要があります。これは、空のコレクションが発生した場合のデフォルト値になります。

val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)

したがって、コレクションを集約して、異なる(非関連)タイプの単一要素(.foldのみで可能)にしたくない場合でも、開始コレクションが空の場合は、最初にコレクションサイズ、次に.reduce、または単に.foldを使用します

val collection: List<Int> = // collection of unknown size

val result1 = if (collection.isEmpty()) 0
              else collection.reduce { x, y -> x + y }

val result2 = collection.fold(0) { x, y -> x + y }

assertEquals(result1, result2)
2
Matt Klein