2010-11-10

Scala: reduceLeft vs foldLeft

Let’s say we have two types: Soccer ball, Auto.

Also, let’s say we have operator +, for which Soccer ball+Soccer ball=Soccer ball and Auto+Soccer ball=Auto. Then, speaking in types:

val a = List(Soccer ball, Soccer ball, Soccer ball, Soccer ball)

a.reduceLeft( (Soccer ball, Soccer ball) => Soccer ball + Soccer ball ) : Soccer ball ==

((Soccer ball+Soccer ball)+Soccer ball)+Soccer ball

a.foldLeft(Auto)( (Auto,Soccer ball) => Auto + Soccer ball ) : Auto ==

(((Auto+Soccer ball)+Soccer ball)+Soccer ball)+Soccer ball

Edge cases:

val b = List[Soccer ball]() //empty list of Soccer ball

b.reduceLeft(_+_) //throw exception

b.foldLeft(Auto)(_+_) //returns Auto

val c = List[](Soccer ball) //list of single Soccer ball

c.reduceLeft(_+_) // returns Soccer ball, the single element in the list

c.foldLeft(Auto)(_+_) //returns Auto, result of operation Auto+Soccer ball

Notice the difference: when list is empty, reduceLeft throws an exception, while foldLeft returns starting value. This can often help to decide which one to use.

Examples:

val a = List(1, 2, 3, 4)

//sum of integers in the list
val sum = a.reduceLeft( (u, v) => u+v )
//integers in the list separated by comma, using reduce
val strRepr1 = a.map( u => u.toString() )
  .reduceLeft( (u, v) => u+","+v ) 
  
//sum of squares, we use Long to support larger values
val sqrSum = a.foldLeft(0L)( (u, v)=> u+v*v )
//number if items in the list
var count = a.foldLeft(0) ( (u, v) => u+1 )
//integers in the list separated by comma, using fold
val strRepr2 = a.tail.foldLeft(a.head.toString())( (u, v) =>
  u+","+v )