Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between fold and reduce?

People also ask

What is the difference between reduce and fold in spark?

fold calls fold on an iterator for each partition, then merges the results, reduce calls reduceLeft on the iterator for each partition then merges the result. The difference is that fold doesn't need to worry about empty partitions or collections, because then it will just use the zero value.

What is reduce in Kotlin?

Kotlin reduce is one of the default methods in the language used to transform or convert the given set of data collections into the single set output results. It also takes the lambda function to operate and combine the pair of data elements. It traverses from the left side to the right side of data collections.

What is fold in Kotlin?

fold takes an initial value, and the first invocation of the lambda you pass to it will receive that initial value and the first element of the collection as parameters. For example, take the following code that calculates the sum of a list of integers: listOf(1, 2, 3).fold(0) { sum, element -> sum + element }

What is folding in Java?

In this post, we will discuss the concept of fold in functional programming: fold functions are used to reduce a data structure containing multiple values into a single one. Associated to the idea of fold are the concepts of... recursion: via recursion, fold traverses the different elements of the data structure.


In addition to what Lee said, you can define reduce in terms of fold, but not (easily) the other way round:

let reduce f list = 
  match list with
  | head::tail -> List.fold f head tail
  | [] -> failwith "The list was empty!"

The fact that fold takes an explicit initial value for the accumulator also means that the result of the fold function can have a different type than the type of values in the list. For example, you can use accumulator of type string to concatenate all numbers in a list into a textual representation:

[1 .. 10] |> List.fold (fun str n -> str + "," + (string n)) ""

When using reduce, the type of accumulator is the same as the type of values in the list - this means that if you have a list of numbers, the result will have to be a number. To implement the previous sample, you'd have to convert the numbers to string first and then accumulate:

[1 .. 10] |> List.map string
          |> List.reduce (fun s1 s2 -> s1 + "," + s2)

Fold takes an explicit initial value for the accumulator while reduce uses the first element of the input list as the initial accumulator value.

This means the accumulator and therefore result type must match the list element type, whereas they can differ in fold as the accumulator is provided separately. This is reflected in the types:

List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
List.reduce : ('T -> 'T -> 'T) -> 'T list -> 'T

In addition reduce throws an exception on an empty input list.


fold is a much more valuable function than reduce. You can define many different functions in terms of fold.

reduce is just a subset of fold.

Definition of fold:

let rec fold f v xs =
    match xs with 
    | [] -> v
    | (x::xs) -> f (x) (fold f v xs )

Examples of functions defined in terms of fold:

let sum xs = fold (fun x y -> x + y) 0 xs

let product xs = fold (fun x y -> x * y) 1 xs

let length xs = fold (fun _ y -> 1 + y) 0 xs

let all p xs = fold (fun x y -> (p x) && y) true xs

let reverse xs = fold (fun x y -> y @ [x]) [] xs

let map f xs = fold (fun x y -> f x :: y) [] xs

let append xs ys = fold (fun x y -> x :: y) [] [xs;ys]

let any p xs = fold (fun x y -> (p x) || y) false xs 

let filter p xs = 
    let func x y =
        match (p x) with
        | true -> x::y
        | _ -> y
    fold func [] xs

Let's look at their signatures:

> List.reduce;;
val it : (('a -> 'a -> 'a) -> 'a list -> 'a) = <fun:clo@1>
> List.fold;;
val it : (('a -> 'b -> 'a) -> 'a -> 'b list -> 'a) = <fun:clo@2-1>

There are some important differences:

  • While reduce works on one type of elements only, the accumulator and list elements in fold could be in different types.
  • With reduce, you apply a function f to every list element starting from the first one:

    f (... (f i0 i1) i2 ...) iN.

    With fold, you apply f starting from the accumulator s:

    f (... (f s i0) i1 ...) iN.

Therefore, reduce results in an ArgumentException on empty list. Moreover, fold is more generic than reduce; you can use fold to implement reduce easily.

In some cases, using reduce is more succinct:

// Return the last element in the list
let last xs = List.reduce (fun _ x -> x) xs

or more convenient if there's not any reasonable accumulator:

// Intersect a list of sets altogether
let intersectMany xss = List.reduce (fun acc xs -> Set.intersect acc xs) xss

In general, fold is more powerful with an accumulator of an arbitrary type:

// Reverse a list using an empty list as the accumulator
let rev xs = List.fold (fun acc x -> x::acc) [] xs