Kiedy należy używać reduceLeft
, reduceRight
, foldLeft
, foldRight
, scanLeft
lub scanRight
?
Chcę intuicji / przeglądu ich różnic - być może z kilkoma prostymi przykładami.
scala
scala-collections
reduce
fold
Marc Grue
źródło
źródło
reduce
ifold
NIE jest istnieniem wartości początkowej - raczej jest to konsekwencja głębszego leżącego u podstaw matematycznego powodu.Odpowiedzi:
Ogólnie rzecz biorąc, wszystkie 6 funkcji składania stosuje operator binarny do każdego elementu kolekcji. Wynik każdego kroku jest przekazywany do następnego kroku (jako dane wejściowe do jednego z dwóch argumentów operatora binarnego). W ten sposób możemy kumulować wynik.
reduceLeft
ireduceRight
zsumuj pojedynczy wynik.foldLeft
ifoldRight
zsumuj pojedynczy wynik, używając wartości początkowej.scanLeft
iscanRight
kumuluje kolekcję pośrednich skumulowanych wyników przy użyciu wartości początkowej.Gromadzić
Od LEWEGO i do przodu ...
Dzięki kolekcji elementów
abc
i operatorowi binarnemuadd
możemy zbadać, co robią różne funkcje składania, przechodząc do przodu od elementu LEFT kolekcji (od A do C):Od PRAWEJ i wstecz ...
Jeśli zaczniemy od elementu PRAWO i przejdziemy wstecz (od C do A), zauważymy, że teraz drugi argument naszego operatora binarnego kumuluje wynik (operator jest taki sam, po prostu zmieniliśmy nazwy argumentów, aby wyjaśnić ich role ):
.
Skumuluj
Od LEWEGO i do przodu ...
Gdybyśmy zamiast tego skumulowali jakiś wynik przez odjęcie, zaczynając od elementu LEFT kolekcji, skumulowalibyśmy wynik za pomocą pierwszego argumentu
res
naszego operatora binarnegominus
:Od PRAWEJ i wstecz ...
Ale wypatruj teraz odmian xRight! Pamiętaj, że (nie-) skumulowana wartość w odmianach xRight jest przekazywana do drugiego parametru
res
naszego operatora binarnegominus
:Ostatnia lista (-2, 3, -1, 4, 0) może nie jest tym, czego byś intuicyjnie oczekiwał!
Jak widzisz, możesz sprawdzić, co robi Twój foldX, po prostu uruchamiając scanX zamiast tego i debugować skumulowany wynik na każdym kroku.
Dolna linia
reduceLeft
lubreduceRight
.foldLeft
lubfoldRight
jeśli masz wartość początkową.Zbierz kolekcję wyników pośrednich za pomocą
scanLeft
lubscanRight
.Użyj odmiany xLeft, jeśli chcesz przejść do przodu przez kolekcję.
źródło
List
aby zastosowaćfoldLeft
. Inne kolekcje mogą wdrażać różne strategie. Ogólnie rzecz biorąc, jeślifoldLeft
ifoldRight
można go stosować zamiennie (właściwość asocjacyjna zastosowanego operatora), wówczasfoldLeft
jest on bardziej wydajny i preferowany.Zwykle metoda REDUCE, FOLD, SCAN polega na gromadzeniu danych na LEWYM i zmienianiu zmiennej PRAWEJ. Główną różnicą między nimi jest REDUKCJA, FOLD to: -
Fold zawsze zaczyna się od
seed
wartości, tj. Wartości początkowej zdefiniowanej przez użytkownika. Reduce zwróci wyjątek, jeśli kolekcja jest pusta, a gdy fold zwróci wartość nasion. Zawsze będzie skutkować pojedynczą wartością.Skanowanie jest używane dla pewnego porządku przetwarzania elementów z lewej lub prawej strony, następnie możemy wykorzystać poprzedni wynik w kolejnych obliczeniach. Oznacza to, że możemy skanować przedmioty. Zawsze przyniesie kolekcję.
RIGHT_REDUCE jest przeciwny do parametru zmniejszonego Left, tzn. Gromadzi wartości w PRAWYM i ciągle zmienia lewą zmienną.
ZmniejszLeftOption i zmniejszRightOption są podobne do left_reduce, a right_reduce różni się tylko tym, że zwracają wyniki w obiekcie OPTION.
Część danych wyjściowych dla wymienionego poniżej kodu to:
za pomocą
scan
operacji na liście liczb (za pomocąseed
wartości0
)List(-2,-1,0,1,2)
{0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 Lista skanowania (0, -2, -3, -3, -2, 0)
{0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 scanLeft (a + b) Lista (0, -2, -3, -3, -2, 0)
{0, -2} => - 2 {-2, -1} => - 3 {-3,0} => - 3 {-3,1} => - 2 {-2,2} => 0 scanLeft (b + a) Lista (0, -2, -3, -3, -2, 0)
{2,0} => 2 {1,2} => 3 {0,3} => 3 {-1,3} => 2 {-2,2} => 0 scanRight (a + b) Lista ( 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)
korzystania
reduce
,fold
operacje na liście ciągówList("A","B","C","D","E")
Kod :
źródło
Dla kolekcji x z elementami x0, x1, x2, x3 i dowolną funkcją f masz:
Podsumowując
scan
jest podobny,fold
ale także emituje wszystkie wartości pośredniereduce
nie potrzebuje wartości początkowej, która czasem jest nieco trudniejsza do znalezieniafold
potrzebuje wartości początkowej, która jest nieco trudniejsza do znalezienia:x.reduceLeft(f) === x.drop(1).foldLeft(x.head,f)
x.foldRight(init,f) === x.reverse.foldLeft(init,f)
x.foldLeft(init,f) === x.scanLeft(init,f).last
źródło