212

との基本的な違いを学びましfoldLeftreduceLeft

foldLeft:

  • 初期値を渡す必要があります

reduceLeft:

  • コレクションの最初の要素を初期値として取ります
  • コレクションが空の場合は例外をスローします

他に違いはありますか?

同様の機能を持つ2つのメソッドがある特定の理由はありますか?

4

8 に答える 8

324

実際の答えを出す前に、ここで言及することはほとんどありません。

  • あなたの質問は とは何の関係もありません。leftむしろ、削減と折りたたみの違いについてです
  • 違いはまったく実装ではありません。署名を見てください。
  • この質問は、特に Scala とは何の関係もありません。むしろ、関数型プログラミングの 2 つの概念に関するものです。

質問に戻る:

これが署名ですfoldLeftfoldRight私がこれから指摘する点でもあった可能性があります):

def foldLeft [B] (z: B)(f: (B, A) => B): B

そして、これが署名ですreduceLeft(ここでも方向は関係ありません)

def reduceLeft [B >: A] (f: (B, A) => B): B

この 2 つは非常に似ているため、混乱を招きました。reduceLeftの特殊なケースですfoldLeft(ちなみに、どちらを使用しても同じことを表現できる場合があります)。

reduceLefta で sayを呼び出すと、List[Int]文字通り、整数のリスト全体が単一の値に縮小されます。これは、型Int(または のスーパータイプInt、したがって[B >: A]) になります。

foldLefta で sayを呼び出すとList[Int]、リスト全体 (紙を転がすことを想像してください) が 1 つの値に折りたたまれますが、この値はInt(したがって[B]) に関連している必要はありません。

次に例を示します。

def listWithSum(numbers: List[Int]) = numbers.foldLeft((List.empty[Int], 0)) {
   (resultingTuple, currentInteger) =>
      (currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}

このメソッドは を受け取り、またはList[Int]を返します。合計を計算し、整数のリストとその合計を含むタプルを返します。ちなみに、代わりにを使用したため、リストは逆向きに返されます。Tuple2[List[Int], Int](List[Int], Int)foldLeftfoldRight

より詳細な説明については、One Fold to rule them all をご覧ください

于 2011-10-14T08:19:25.770 に答える
202

reduceLeft便利な方法です。と同等です

list.tail.foldLeft(list.head)(_)
于 2011-10-14T08:17:53.610 に答える
49

foldLeftはより一般的ですが、最初に入力したものとはまったく異なるものを生成するために使用できます。一方reduceLeft、コレクション型の同じ型またはスーパー型の最終結果しか生成できません。例えば:

List(1,3,5).foldLeft(0) { _ + _ }
List(1,3,5).foldLeft(List[String]()) { (a, b) => b.toString :: a }

foldLeft、最後に折り畳まれた結果 (初回は初期値を使用) と次の値でクロージャを適用します。

reduceLeft一方、最初にリストから2つの値を結合し、それらをクロージャーに適用します。次に、残りの値を累積結果と結合します。見る:

List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }

リストが空の場合foldLeft、有効な結果として初期値を提示できます。reduceLeft一方、リスト内に少なくとも 1 つの値が見つからない場合、有効な値はありません。

于 2011-10-14T08:20:26.017 に答える
6

参考reduceLeftまでに、空のコンテナに適用すると以下のエラーでエラーになります。

java.lang.UnsupportedOperationException: empty.reduceLeft

使用するコードを作り直す

myList foldLeft(List[String]()) {(a,b) => a+b}

可能性のあるオプションの 1 つです。もう 1 つはreduceLeftOption、オプションでラップされた結果を返すバリアントを使用することです。

myList reduceLeftOption {(a,b) => a+b} match {
  case None    => // handle no result as necessary
  case Some(v) => println(v)
}
于 2013-06-26T16:29:17.223 に答える
5

それらが両方とも Scala 標準ライブラリにある基本的な理由は、おそらく両方とも Haskell 標準ライブラリ ( と と呼ばれるfoldl)にあるためfoldl1です。そうreduceLeftでない場合は、さまざまなプロジェクトで便利なメソッドとして定義されることがよくあります。

于 2011-10-14T08:23:56.023 に答える
4

Scala の関数型プログラミングの原則(Martin Odersky)から:

関数reduceLeftは、より一般的な関数 で定義されますfoldLeft

foldLeftは似ていますが、追加のパラメーターとしてaccumulatorreduceLeftを取り、空のリストで呼び出されたときに返されます。 zfoldLeft

(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x

reduceLeft[空のリストで呼び出されたときに例外をスローする とは対照的です。]

このコース (講義 5.5 を参照) では、これらの関数の抽象的な定義を提供し、それらの違いを示していますが、パターン マッチングと再帰の使い方は非常に似ています。

abstract class List[T] { ...
  def reduceLeft(op: (T,T)=>T) : T = this match{
    case Nil     => throw new Error("Nil.reduceLeft")
    case x :: xs => (xs foldLeft x)(op)
  }
  def foldLeft[U](z: U)(op: (U,T)=>U): U = this match{
    case Nil     => z
    case x :: xs => (xs foldLeft op(z, x))(op)
  }
}

foldLeftは type の値を返すことに注意してくださいU。これは必ずしも と同じ型ではありませんList[T]が、reduceLeft はリストと同じ型の値を返します)。

于 2017-02-01T22:11:19.963 に答える
0

fold/reduce で何をしているのかを本当に理解するには、これをチェックしてください: http://wiki.tcl.tk/17983 非常に良い説明。折り畳みの概念を理解したら、reduce は上記の答えと一緒になります: list.tail.foldLeft(list.head)(_)

于 2015-07-06T10:21:39.030 に答える