いつreduceLeft
、reduceRight
、foldLeft
、foldRight
、scanLeft
、またはscanRight
を使用する必要がありますか?
私はそれらの違いの直観/概要を望みます-おそらくいくつかの簡単な例を使って。
一般に、6つの折り畳み関数はすべて、コレクションの各要素に2項演算子を適用します。各ステップの結果は、次のステップに渡されます(2項演算子の2つの引数の1つへの入力として)。この方法で結果を累積できます。
reduceLeft
およびreduceRight
は、単一の結果を累積します。
foldLeft
およびfoldRight
は、開始値を使用して単一の結果を累積します。
scanLeft
およびscanRight
は、開始値を使用して中間累積結果のコレクションを累積します。
左から順方向...
要素abc
およびバイナリ演算子add
のコレクションを使用すると、コレクションのLEFT要素から(AからCへ)進むときにさまざまなfold関数が何を行うかを調べることができます。
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)に進むと、バイナリ演算子へのsecond引数が結果を蓄積することに気付くでしょう(演算子は同じです。役割を明確にするために引数名を変更しました):
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要素から始まる減算によって結果をde-cumulateする場合、最初の引数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バリエーションの(デ)累積値は、バイナリ演算子res
のsecondパラメーター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)
最後のリスト(-2、3、-1、4、0)は、直感的に期待するものではないかもしれません!
ご覧のとおり、scanXを実行するだけでfoldXの動作を確認し、各ステップで累積結果をデバッグできます。
reduceLeft
またはreduceRight
で結果を累積します。foldLeft
またはfoldRight
で結果を累積します。scanLeft
またはscanRight
を使用して、中間結果のコレクションを累積します。
コレクションをforwardsしたい場合は、xLeftバリエーションを使用します。
通常、REDUCE、FOLD、SCANメソッドは、LEFTにデータを蓄積し、RIGHT変数を変更し続けることで機能します。それらの主な違いはREDUCE、FOLDです:-
Foldは常にseed
値、つまりユーザー定義の開始値で始まります。 foldがシード値を返すところでコレクションが空の場合、Reduceは例外をスローします。 常に単一の値になります。
スキャンは、左側または右側からのアイテムの処理順序に使用され、その後の計算で以前の結果を利用できます。つまり、アイテムをスキャンできます。 常にコレクションになります。
RIGHT_REDUCEはreduceLeftの1とは反対です。つまり、RIGHTに値を蓄積し、左の変数を変更し続けます。
reduceLeftOptionとreduceRightOptionは、left_reduceとright_reduceに似ていますが、OPTIONオブジェクトで結果を返す点が異なります。
下記のコードの出力の一部は次のようになります。
数値のリストに対するscan
操作の使用(seed
値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}))
}