reduceLeft
、reduceRight
、foldLeft
、foldRight
、scanLeft
またはをいつ使用する必要がありscanRight
ますか?
それらの違いの直感/概要が必要です-おそらくいくつかの簡単な例があります。
reduceLeft
、reduceRight
、foldLeft
、foldRight
、scanLeft
またはをいつ使用する必要がありscanRight
ますか?
それらの違いの直感/概要が必要です-おそらくいくつかの簡単な例があります。
一般に、6 つのフォールド関数はすべて、コレクションの各要素に二項演算子を適用します。各ステップの結果は、次のステップに渡されます (二項演算子の 2 つの引数の 1 つへの入力として)。このようにして、結果を累積できます。
reduceLeft
reduceRight
単一の結果を累積します。
foldLeft
foldRight
開始値を使用して単一の結果を累積します。
scanLeft
scanRight
開始値を使用して中間累積結果のコレクションを累積します。
左から前へ...
要素のコレクションabc
と二項演算子add
を使用して、コレクションの LEFT 要素から (A から C に) 進むときに、さまざまな折り畳み関数が何をするかを調べることができます。
val abc = List("A", "B", "C")
def add(res: String, x: String) = {
println(s"op: $res + $x = ${res + x}")
res + x
}
abc.reduceLeft(add)
// op: A + B = AB
// op: AB + C = ABC // accumulates value AB in *first* operator arg `res`
// res: String = ABC
abc.foldLeft("z")(add) // with start value "z"
// op: z + A = zA // initial extra operation
// op: zA + B = zAB
// op: zAB + C = zABC
// res: String = zABC
abc.scanLeft("z")(add)
// op: z + A = zA // same operations as foldLeft above...
// op: zA + B = zAB
// op: zAB + C = zABC
// res: List[String] = List(z, zA, zAB, zABC) // maps intermediate results
右から後ろへ…
RIGHT 要素から始めて逆方向 (C から A) に進むと、2 項演算子の2 番目の引数が結果を累積していることに気付くでしょう (演算子は同じで、役割を明確にするために引数名を変更しただけです)。 ):
def add(x: String, res: String) = {
println(s"op: $x + $res = ${x + res}")
x + res
}
abc.reduceRight(add)
// op: B + C = BC
// op: A + BC = ABC // accumulates value BC in *second* operator arg `res`
// res: String = ABC
abc.foldRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: String = ABCz
abc.scanRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: List[String] = List(ABCz, BCz, Cz, z)
.
左から前へ...
代わりに、コレクションの LEFT 要素から開始する減算によって一部の結果を逆累積res
する場合は、二項演算子の最初の引数を介して結果を累積しminus
ます。
val xs = List(1, 2, 3, 4)
def minus(res: Int, x: Int) = {
println(s"op: $res - $x = ${res - x}")
res - x
}
xs.reduceLeft(minus)
// op: 1 - 2 = -1
// op: -1 - 3 = -4 // de-cumulates value -1 in *first* operator arg `res`
// op: -4 - 4 = -8
// res: Int = -8
xs.foldLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: Int = -10
xs.scanLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: List[Int] = List(0, -1, -3, -6, -10)
右から後ろへ…
ただし、xRight のバリエーションに注目してください。xRight バリエーションの (逆) 累積値は、 2項演算子の2 番目のパラメーターに渡されることに注意してください。res
minus
def minus(x: Int, res: Int) = {
println(s"op: $x - $res = ${x - res}")
x - res
}
xs.reduceRight(minus)
// op: 3 - 4 = -1
// op: 2 - -1 = 3 // de-cumulates value -1 in *second* operator arg `res`
// op: 1 - 3 = -2
// res: Int = -2
xs.foldRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: Int = -2
xs.scanRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: List[Int] = List(-2, 3, -1, 4, 0)
最後の List(-2, 3, -1, 4, 0) は、直感的に期待するものではないかもしれません!
ご覧のとおり、代わりに scanX を実行するだけで foldX が何をしているかを確認し、各ステップで累積された結果をデバッグできます。
reduceLeft
またはで結果を累積しreduceRight
ます。foldLeft
またはで結果を累積します。foldRight
scanLeft
またはを使用して、中間結果のコレクションを累積しscanRight
ます。
コレクションを順方向に進めたい場合は、xLeft バリエーションを使用します。
通常、REDUCE、FOLD、SCAN メソッドは、LEFT にデータを蓄積し、RIGHT 変数を変更し続けることによって機能します。それらの主な違いは、REDUCE、FOLD です。
折り畳みは常に値、seed
つまりユーザー定義の開始値で始まります。コレクションが空の場合、reduce は例外をスローしますが、fold はシード値を返します。常に単一の値になります。
スキャンは、左側または右側からのアイテムの処理順序に使用され、その後の計算で前の結果を利用できます。つまり、アイテムをスキャンできます。常にコレクションになります。
RIGHT_REDUCE は reduceLeft の反対です。つまり、RIGHT に値を蓄積し、左の変数を変更し続けます。
reduceLeftOption と reduceRightOption は left_reduce と right_reduce に似ていますが、OPTION オブジェクトで結果を返す点だけが異なります。
以下のコードの出力の一部は次のようになります:-
scan
数値のリストに対する操作の使用 ( valueseed
を使用0
)List(-2,-1,0,1,2)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0スキャンリスト(0, -2, -3, -3, -2, 0)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0 scanLeft (a+b) List(0, -2, -3, -3, -2, 0)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0 scanLeft (b+a) List(0, -2, -3, -3, -2, 0)
{2,0}=>2 {1,2}=>3 {0,3}=>3 {-1,3}=>2 {-2,2}=>0 scanRight (a+b) List( 0, 2, 3, 3, 2, 0)
{2,0}=>2 {1,2}=>3 {0,3}=>3 {-1,3}=>2 {-2,2}=>0 scanRight (b+a) List( 0, 2, 3, 3, 2, 0)
を使用してreduce
、fold
文字列のリストに対する操作List("A","B","C","D","E")
コード :
object ScanFoldReduce extends App {
val list = List("A","B","C","D","E")
println("reduce (a+b) "+list.reduce((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (a+b) "+list.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (b+a) "+list.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("reduceRight (a+b) "+list.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("reduceRight (b+a) "+list.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" ")
b+a
}))
println("scan "+list.scan("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (a+b) "+list.scanLeft("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (b+a) "+list.scanLeft("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("scanRight (a+b) "+list.scanRight("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanRight (b+a) "+list.scanRight("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
//Using numbers
val list1 = List(-2,-1,0,1,2)
println("reduce (a+b) "+list1.reduce((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (a+b) "+list1.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (b+a) "+list1.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println(" reduceRight (a+b) "+list1.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println(" reduceRight (b+a) "+list1.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" ")
b+a
}))
println("scan "+list1.scan(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (a+b) "+list1.scanLeft(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (b+a) "+list1.scanLeft(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("scanRight (a+b) "+list1.scanRight(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b}))
println("scanRight (b+a) "+list1.scanRight(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
b+a}))
}