Instructor: Stefan Mitsch
How to combine collection elements into an aggregate result?
Express by iterating through the list
Java
int sum (List<Int> xs) { int result = 0; for (x : xs) result += x; return result;}
Scala
def sum (xs:List[Int]) : Int = { var result = 0 for x <- xs do result += x result} ensuring { case result => ??? }
xs
Express with a recursive function
def sum (xs:List[Int]) : Int = xs match case Nil => 0 case y :: ys => y + sum (ys)val xs = List(11,21,31)sum (xs)
sum(11::21::31::Nil)--> sum(11::21::31::Nil)--> 11 + sum(21::31::Nil)--> 11 + (21 + sum(31::Nil))--> 11 + (21 + (31 + sum(Nil)))--> 11 + (21 + (31 + 0))--> 11 + (21 + 31)--> 11 + 52--> 63 = (11 + (21 + (31 + 0)))
With a different zero element
def sum (xs:List[Int], z:Int = 0) : Int = xs match case Nil => z case y :: ys => y + sum (ys, z)val xs = List(11,21,31)sum (xs)
sum(11::21::31::Nil)--> sum(11::21::31::Nil, 0)--> 11 + sum(21::31::Nil, 0)--> 11 + (21 + sum(31::Nil, 0))--> 11 + (21 + (31 + sum(Nil, 0)))--> 11 + (21 + (31 + 0))--> 11 + (21 + 31)--> 11 + 52--> 63 = (11 + (21 + (31 + 0)))
Sum of elements in a list computing forward
def sum (xs:List[Int], z:Int = 0) : Int = xs match case Nil => z case y :: ys => sum (ys, z + y)val xs = List(11,21,31)sum (xs)
sum(11::21::31::Nil)--> sum(11::21::31::Nil, 0)--> sum(21::31::Nil, 11)--> sum(31::Nil, 32)--> sum(Nil, 63)-->-->-->--> 63 = (((0 + 11) + 21) + 31)
generalize the + operation
+
def sum (xs:List[Int], z:Int) : Int = xs match case Nil => z case y::ys => sum (ys, z + y)val xs = List(11,21,31)sum (xs, 0)
res1: Int = 63
def foldLeft (xs:List[Int], z:Int, f:((Int,Int)=>Int)) : Int = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f)val xs = List(11,21,31)foldLeft (xs, 0, _+_)
Change the return type
def foldLeft (xs:List[Int], z:String, f:(String,Int)=>String) : String = xs match case Nil => z case y::ys => foldLeft (ys, f(z, y), f)val xs = List(11,21,31)foldLeft (xs, "", _ + " " + _)
res1: String = "11 21 31 "
Changing the parameter type
def foldLeft (xs:List[List[Int]], z:Int, f:(Int,List[Int])=>Int) : Int = xs match case Nil => z case y::ys => foldLeft (ys, f(z, y), f)val xss = List(List(11,21,31),List(),List(41,51))foldLeft (xss, 0, _ + _.length)
res1: Int = 5
Abstracting the type
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f)val xs = List(11,21,31)foldLeft (xs, "!", (z:String,x:Int) => z + " " + x)
res1: String = "! 11 21 31"
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match case Nil => z case y::ys => f (y, foldRight (ys, z, f))val xs = List(11,21,31)foldRight (xs, "!", (x:Int,z:String) => x + " " + z)
res1: String = "11 21 31 !"
List
fold
xss.foldLeft (0) ((z,xs)=>z + xs.length)
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match { case Nil => z case y::ys => foldLeft (ys, f(z,y), f)}
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match { case Nil => z case y::ys => f (y, foldRight (ys, z, f))}
foldLeft
return foldLeft (ys, f(z, y))
f
foldRight
return f (y, foldRight (ys, z))
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f)
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match case Nil => z case y::ys => f (y, foldRight (ys, z, f))
val xs = List(a, b, c)foldLeft (xs, z, f) === f( f( f(z,a),b),c)foldRight(xs, z, f) === f(a, f(b, f(c,z)))
xs.foldLeft(z)(f) xs.foldRight(z)(f) f f / \ / \ f c a f / \ / \ f b b f / \ / \ z a c z
def sum (xs: List[Int]) = xs.foldLeft(0)(_+_)def prod (xs: List[Int]) = xs.foldLeft(1)(_*_)def or (xs: List[Boolean]) = xs.foldLeft(false)(_||_)def and (xs: List[Boolean]) = xs.foldLeft(true)(_&&_)def append [X] (xs: List[X])(ys: List[X]) = xs.foldRight(ys)(_::_)def flatten [X] (xs: List[List[X]]) = xs.foldLeft(Nil:List[X])(_:::_)def length [X] (xs: List[X]) = xs.foldLeft(0)((z,x)=>z+1)def reverse [X] (xs: List[X]) = xs.foldRight(Nil:List[X])((x,zs)=>zs:::List(x))def map [X,Y] (xs: List[X], f: X=>Y) = xs.foldRight(Nil:List[Y])(f(_)::_)def filter [X] (xs: List[X], f: X=>Boolean) = xs.foldRight(Nil:List[X])((x,zs)=>if f(x) then x::zs else zs)