Previously, Nicolas Rinaudo answered my question on Scala's List foldRight Always Using foldLeft?
Studying Haskell currently, my understanding is that foldRight
should be preferred over foldLeft
in cases where ::
(prepend) can be used over ++
(append).
The reason, as I understand, is performance - the former occurs in O(1)
, i.e. add an item to the front - constant time. Whereas the latter requires O(N)
, i.e. go through the whole list and add an item.
In Scala, given that foldLeft
is implemented in terms of foldRight
, does the benefit of using :+
over ++
with foldRight
even matter since foldRight
gets reversed, and then foldLeft'd
?
As an example, consider this simple fold..
operation for simply returning a list's elements in order.
foldLeft
folds over each element, adding each item to the list via :+
.
scala> List("foo", "bar").foldLeft(List[String]()) { (acc, elem) => acc :+ elem } res9: List[String] = List(foo, bar)
foldRight
performs a foldLeft with ::
operator on each item, but then reverses.
scala> List("foo", "bar").foldRight(List[String]()) { (elem, acc) => elem :: acc } res10: List[String] = List(foo, bar)
In reality, does it matter in Scala which foldLeft
or foldRight
to use given that foldRight
uses foldRight
?
The primary difference is the order in which the fold operation iterates through the collection in question. foldLeft starts on the left side—the first item—and iterates to the right; foldRight starts on the right side—the last item—and iterates to the left. fold goes in no particular order.
foldLeft() method is a member of TraversableOnce trait, it is used to collapse elements of collections. It navigates elements from Left to Right order. It is primarily used in recursive functions and prevents stack overflow exceptions.
The Scala foldLeft method can be used to iterate over a data structure and perform multiple operations on a Spark DataFrame. foldLeft can be used to eliminate all whitespace in multiple columns or convert all the column names in a DataFrame to snake_case.
The foldRight method takes an associative binary operator function as parameter and will use it to collapse elements from the collection. The order for traversing the elements in the collection is from right to left and hence the name foldRight. The foldRight method allows you to also specify an initial value.
@Rein Henrichs' answer is indeed irrelevant to Scala, because Scala's implementation of foldLeft
and foldRight
is completely different (for starters, Scala has eager evaluation).
foldLeft
and foldRight
themselves have actually very little to do wrt the performance of your program. Both are (liberally speaking) O(n*c_f) where c_f is the complexity of one call to the function f
that is given. foldRight
is slower by a constant factor because of the additional reverse
, though.
So the real factor that differentiates one from the other is the complexity of the anonymous function that you give. Sometimes, it is easier to write an efficient function designed to work with foldLeft
, and sometimes to foldRight
. In your example, the foldRight
version is best, because the anonymous function that you give to foldRight
is O(1). In contrast, the anonymous function that you give to foldLeft
is O(n) itself (amortized, which is what matters here), because acc
keeps growing from 0 to n-1, and appending to a list of n elements is O(n).
So it actually matters whether you choose foldLeft
or foldRight
, but not because of these functions themselves, but because of the anonymous functions given to them. If both are equivalent, choose foldLeft
by default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With