it-swarm.com.de

Verkleinern, Falzen oder Scannen (Links / Rechts)?

Wann sollte ich reduceLeft, reduceRight, foldLeft, foldRight, scanLeft oder scanRight verwenden?

Ich möchte einen Überblick über ihre Unterschiede - möglicherweise mit einigen einfachen Beispielen.

171
Marc Grue

Im Allgemeinen wenden alle 6 Faltfunktionen einen binären Operator auf jedes Element einer Sammlung an. Das Ergebnis jedes Schritts wird an den nächsten Schritt weitergeleitet (als Eingabe für eines der beiden Argumente des Binäroperators). Auf diese Weise können wir kumulieren ein Ergebnis erzielen.

reduceLeft und reduceRight kumulieren ein einzelnes Ergebnis.

foldLeft und foldRight addieren ein einzelnes Ergebnis mit einem Startwert.

scanLeft und scanRight kumulieren eine Sammlung von kumulativen Zwischenergebnissen unter Verwendung eines Startwerts.

Akkumulieren

von LINKS und vorwärts ...

Mit einer Auflistung von Elementen abc und einem binären Operator add können wir untersuchen, was die verschiedenen Fold-Funktionen tun, wenn Sie vom LEFT-Element der Auflistung (von A nach C) vorwärts gehen:

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


von RECHTS und rückwärts ...

Wenn wir mit dem Element RIGHT beginnen und rückwärts gehen (von C nach A), werden wir feststellen, dass jetzt das Argument second für unseren Binäroperator das Ergebnis akkumuliert (der Operator ist der gleiche, wir nur) Die Argumentnamen wurden geändert, um ihre Rollen zu verdeutlichen.

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)

.

Entkumulieren

von LINKS und vorwärts ...

Wenn wir stattdessen de-cumulate ein Ergebnis durch Subtraktion ab dem LEFT-Element einer Sammlung erhalten würden, würden wir das Ergebnis durch das erste Argument res unseres Binäroperators 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)


von RECHTS und rückwärts ...

Aber achten Sie jetzt auf die xRight-Varianten! Denken Sie daran, dass der (de-) kumulierte Wert in den xRight-Variationen an den Parameter secondres unseres Binäroperators minus übergeben wird:

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) 

Die letzte Liste (-2, 3, -1, 4, 0) ist möglicherweise nicht das, was Sie intuitiv erwarten würden!

Wie Sie sehen, können Sie überprüfen, was Ihr foldX tut, indem Sie stattdessen einfach einen scanX ausführen und das kumulierte Ergebnis bei jedem Schritt debuggen.

Endeffekt

  • Kumulieren Sie ein Ergebnis mit reduceLeft oder reduceRight.
  • Kumulieren Sie ein Ergebnis mit foldLeft oder foldRight, wenn Sie einen Startwert haben.
  • Sammeln Sie eine Sammlung von Zwischenergebnissen mit scanLeft oder scanRight.

  • Verwenden Sie eine xLeft-Variante, wenn Sie vorwärts durch die Sammlung gehen möchten.

  • Verwenden Sie eine xRight-Variante, wenn Sie rückwärts durch die Sammlung gehen möchten.
351
Marc Grue

Normalerweise wird die Methode REDUCE, FOLD, SCAN ausgeführt, indem Daten auf LEFT gesammelt werden und die Variable RIGHT weiter geändert wird. Hauptunterschied zwischen ihnen ist REDUCE, FOLD ist: -

Fold beginnt immer mit einem seed Wert, d. H. Einem benutzerdefinierten Startwert. "Reduzieren" löst eine Ausnahme aus, wenn die Sammlung leer ist und "Als Falz" den Startwert zurückgibt. Ergibt immer einen einzelnen Wert.

Scan wird für einige Verarbeitungsreihenfolgen von Artikeln von links oder rechts verwendet, dann können wir das vorherige Ergebnis für die nachfolgende Berechnung verwenden. Das heißt, wir können Objekte scannen. Ergibt immer eine Sammlung.

  • Die Methode LEFT_REDUCE funktioniert ähnlich wie die Methode REDUCE.
  • RIGHT_REDUCE ist entgegengesetzt zu ReductionLeft One, d. H. Es akkumuliert Werte in RIGHT und ändert die linke Variable weiter.

  • reduLeftOption und reduRightOption ähneln left_reduce und right_reduce. Der einzige Unterschied besteht darin, dass sie Ergebnisse im OPTION-Objekt zurückgeben.

Ein Teil der Ausgabe für den unten genannten Code wäre:

mit scan Operation über eine Liste von Zahlen (mit seed Wert 0) List(-2,-1,0,1,2)

  • {0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 Scan-Liste (0, -2, -3, -3, -2, 0)

  • {0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 scanLeft (a + b) Liste (0, -2, -3, -3, -2, 0)

  • {0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 scanLeft (b + a) Liste (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)

mit reduce, fold Operationen über eine Liste von Strings List("A","B","C","D","E")

  • {A, B} => AB {AB, C} => ABC {ABC, D} => ABCD {ABCD, E} => ABCDE reduziere (a + b) ABCDE
  • {A, B} => AB {AB, C} => ABC {ABC, D} => ABCD {ABCD, E} => ABCDE reduLeft (a + b) ABCDE
  • {A, B} => BA {BA, C} => CBA {CBA, D} => DCBA {DCBA, E} => EDCBA reduLeft (b + a) EDCB
  • {D, E} => DE {C, DE} => CDE {B, CDE} => BCDE {A, BCDE} => ABCDE reduRight (a + b) ABCDE
  • {D, E} => ED {C, ED} => EDC {B, EDC} => EDCB {A, EDCB} => EDCBA reduRight (b + a) EDCBA

Code:

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}))
}
8
Puneeth Reddy V