I have two examples of foldLeft
that I cannot really grasp the logic.
First example:
val donuts: List[String] = List("Plain", "Strawberry", "Glazed")
println(donuts.foldLeft("")((acc, curr) => s" $acc, $curr Donut ")) // acc for accumulated, curr for current
This will give
, Plain Donut , Strawberry Donut , Glazed Donut
Does not foldLeft
accumulate value that was earlier?
I was expecting the result to be
, Plain Donut , Plain Strawberry Donut , Strawberry Glazed Donut
Second example:
def multi(num:Int,num1:Int):Int=num*10
(1 until 3).foldLeft(1)(multi)
Can someone explain what is happening in every step? I cannot see how this can become 100. Also, the second argument multi
is a function. Why does it not take any input variables (num and num1)?
CodePudding user response:
Does not
foldLeft
accumulate value that was earlier?
yes it does. It uses result of previous iteration and current element and produces new result (using the binary operator you have provided) so for the first example next steps are happening:
the start value of accumulator -
""
acc = ""
,curr = "Plain"
->" , Plain Donut "
acc = " , Plain Donut "
,curr = "Strawberry"
->" , Plain Donut , Strawberry Donut "
acc = " , Plain Donut , Strawberry Donut "
,curr = "Strawberry"
->" , Plain Donut , Strawberry Donut , Glazed Donut"
For the second example current value is simply ignored - i.e. multi
can be rewritten as def multi(acc:Int, curr:Int):Int = acc*10
where curr
is not actually used so foldLeft
simply multiplies starting value (1
) by 10 n
times where n
is number of elements in the sequence (i.e. (1 until 3).length
which is 2).
Why does it not take any input variables (num and num1)?
foldLeft
is a function which accepts a function. It accepts
a generic function which in turn accepts two parameters and returns result of the same type as the first parameter (op: (B, A) => B
, where B
is the the result type and A
is sequence element type). multi
matches this definition when B
== A
== Int
and is passed to the foldLeft
which will internally provide the input variables on the each step.
CodePudding user response:
A left fold needs three things: a list to works on, an initial value, and a function.
That function takes each element of the list and applies it to the initial value. Each time, the initial value is the result of the previous fucntion application.
Summing a list is a great toy example.
val nums = List(1, 2, 3, 4)
val total = nums.foldLeft(0)((a, b) => a b)
total
is 10
.
That initial value has to pass all of the state you need. Currently, you pass the accumulated string. What you should be passing is a tuple giving your function extra information to work with: the accumulated string, and a string representing the previous element in the list.
Your result would look something like:
("Plain donut, ...", "Glazed")
Then you just need to select out the accumulated string and discard the second element.