Kotlinのフォールドとリデュースの基本的な違いは何ですか?いつ使用するのですか?


130

私はかなりこの両方の機能と混同していますfold()し、reduce()Kotlinで、缶誰も私にそれらの両方を区別し、具体的な例を与えますか?



4
見ていこれは、このトピックの深い根本的な議論のために
GhostCat

2
@LunarWatcher、私はそれらのドキュメントを見ましたが、それを取得できませんでした、それはあなたが投稿した質問です、あなたは例を挙げられますか?
TapanHP

1
@MattKlein完了
Jayson Minard

回答:


280

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操作が、それを適用するコレクション内の値以外の値に依存しない場合に使用できます。


47
いい説明だ!また、空のコレクションを削減することはできませんが、折りたたむことはできます。
Miha_x64 2017年

ほら、Kotlinの非常に初心者レベルのm、あなたが与えた最初の例は、いくつかの手順と最後の答えでそれをさらに説明できますか?
助かり

3
@TapanHP emptyList<Int>().reduce { acc, s -> acc + s }は例外を生成しますが、問題ありませんemptyList<Int>().fold(0) { acc, s -> acc + s }
Miha_x64 2017年

31
reduceはまた、ラムダの戻りをリストメンバーと同じ型に強制しますが、これはフォールドには当てはまりません。これは、リストの最初の要素、つまりアキュムレータの初期値を作成することの重要な結果です。
andresp

4
@andresp:完全を期すためのメモとして:同じ型である必要はありません。リストメンバーはアキュムレータのサブタイプにすることもできます。これは機能しますlistOf<Int>(1, 2).reduce { acc: Number, i: Int -> acc.toLong() + i }(リストタイプはIntで、アキュムレータタイプはNumberとして宣言され、実際にはLongです)
Boris

11

(他の回答のコメントに記載されていますが、理解するのは難しいかもしれません)空のコレクションに対して実行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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.