2 FoldLefts are Equal - scala

Why do both of the following foldLeft's result in the same output?
#1
scala> List(1,2,3).foldLeft(List[Int]())( (acc, el) => acc :+ el)
res114: List[Int] = List(1, 2, 3)
And, now using _ :+ _ as the (B, A) => B argument.
#2
scala> List(1,2,3).foldLeft(List[Int]())(_ :+ _)
res115: List[Int] = List(1, 2, 3)
In particular, the lack of explicitly appending to the accumulator in the second case confuses me.

_ :+ _ is simply a shorthand for (x1, x2) => x1 :+ x2, just as list.map(_.toString) is simply list.map(x => x.toString).
See more on the placeholder syntax here.

Related

Pattern matching for list of pairs scala

I have been trying to learn pattern matching and pairs in Scala and use it to implement the merge sort but the pattern matching. But the pattern match to extract head and tail pair doesn't work. What is it which I am missing in the below code?
def merge(xs: List[Int], ys: List[Int]): List[Int] =
(xs, ys) match {
case (x: Int, y: Int) :: (xs1: List[Int], ys1: List[Int]) =>
if (x < y) x :: merge(xs1, ys)
else y :: merge(xs, ys1)
case (x: List[Int], Nil) => x
case (Nil, y: List[Int]) => y
}
you have a syntax error in your 1st case statement, change it to
case (x :: xs1 , y :: ys1)
from
case (x: Int, y: Int) :: (xs1: List[Int], ys1: List[Int])
You are trying to match a tuple containing Lists, not List of Tuples

for comprehension in scala for implementing flatMap

Prof. Odersky in Coursera course has implemented flatMap using for loops as following:
def flatMap[T, U](xs: List[T], f: T => Iterable[U]) = for (x <- xs; y <- f(x)) yield y
And here's some application on the two functions (result as expected):
val xs = List(1, 2, 3, 4, 5)
flatMap[Int, Int](xs, x=> List(x /2))
However, When I try implement the flatMap as:
for (x <- xs) yield f(x)
It does not return the correct answer, it returns a List of Lists (it should return one big list contains all elements of the inner lists)
My question is, What is the different that make flatMap works as expected; between both:
for (x <- xs; y <- f(x)) yield y
//And
for (x <- xs) yield f(x)
And Why for (x <- xs; y <- x * x) yield y not compiling?
Your second version doesn't involve a call to flatMap at all. You can use reify to de-sugar the for comprehension and see:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> val f: Int => Iterable[Int] = null
f: Int => Iterable[Int] = null
scala> val xs = List(1, 2, 3, 4, 5)
xs: List[Int] = List(1, 2, 3, 4, 5)
scala> reify { for (x <- xs; y <- f(x)) yield y }
res0: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]]($read.xs.flatMap(((x) => $read.f.apply(x).map(((y) => y))(Iterable.canBuildFrom)))(List.canBuildFrom))
scala> reify { for (x <- xs) yield f(x) }
res1: reflect.runtime.universe.Expr[List[Iterable[Int]]] = Expr[List[scala.Iterable[Int]]]($read.xs.map(((x) => $read.f.apply(x)))(List.canBuildFrom))
the first can be simplified to:
xs.flatMap(x => f(x).map(identity))
which is equivalent to:
xs.flatMap(f)
and the second can be simplified to:
xs.map(f)

Folding a list of tuples using Scala

What's wrong with this simple scala code?
val l = List(("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5))
l.fold(0) {(acc: Int, tup: (String, Int)) => acc + tup._2}
:9: error: type mismatch;
found : (Int, (String, Int)) => Int
required: (Any, Any) => Any
l.fold(0) {(acc: Int, tup: (String, Int)) => acc + tup._2}
In other functional languages (e.g., f#) this works:
let l = [("a", 1); ("b", 2); ("c", 3); ("d", 4)];;
List.fold(fun accm tup -> accm + (snd tup)) 0 l;;
val it : int = 10
The fold method assumes an associative operator and can in theory (e.g. when using parallelism) be performed in arbitrary order. The signature thus makes it clear that the accumulating type must be a super-type of the collection's element:
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
The inferred super-type of (String, Int) and Int is Any.
This is all described in the API documentation.
What you want is a foldLeft or foldRight which do not have this restriction on the type:
def foldLeft[B](z: B)(f: (B, A) ⇒ B): B
Therefore:
l.foldLeft(0) { (acc, tup) => acc + tup._2 }
or
(0 /: l) { case (acc, (_, n)) => acc + n }

Sort elements as part of concatenating elements of 2 Lists

Here is a function I wrote for concatenating elements of a List using an accumulator with tail recursion :
val l1 = List(1, 2, 3) //> l1 : List[Int] = List(1, 2, 3)
val l2 = List(1, 2, 3) //> l2 : List[Int] = List(1, 2, 3)
def func(l1: List[Int], l2: List[Int], acc: List[Int]): List[Int] = {
(l1, l2) match {
case (Nil, Nil) => acc.reverse
case (h1 :: t1, h2 :: t2) => {
func(t1, t2, h1 :: h2 :: acc)
}
}
} //> func: (l1: List[Int], l2: List[Int], acc: List[Int])List[Int]
func(l1, l2, List()) //> res0: List[Int] = List(1, 1, 2, 2, 3, 3)
This is my understanding of the call order
func( 1 :: 1 :: () )
func( 2 :: 2 :: 1 :: 1 : () )
func( 3 :: 3 :: 2 :: 2 :: 1 :: 1 : () )
So the call order is the reason why I must call reverse on base call of acc so that the List is ordered in same ordering initial List elements. To try to minimize the steps required to concatenate the lists I have tried to add the elements like this :
func(t1, t2, acc :: h1 :: h2)
instead of
func(t1, t2, h1 :: h2 :: acc)
but receive compile time error :
value :: is not a member of Int
So it seems I cannot prepend these elements to this List ?
When you write x :: y, y must be a list and x the element you want to prepend.
You can use acc :+ h1 :+ h2 to append h1 and h2 to acc, but note that adding elements to the end of the list is a relatively expensive operation (linear with the length of the list).

scala: yield pairwise combinations of two loops

I would like to create a collection with tuples containing all pairwise combinations of two lists. Something like:
for ( x <- xs )
for ( y <- ys )
yield (x,y)
In Python this would work, in Scala apparently for yields only for the last loop (so this evaluates to Unit)
What is the cleanest way to implement it in Scala?
You were almost there:
scala> val xs = List (1,2,3)
xs: List[Int] = List(1, 2, 3)
scala> val ys = List (4,5,6)
ys: List[Int] = List(4, 5, 6)
scala> for (x <- xs; y <- ys) yield (x,y)
res3: List[(Int, Int)] = List((1,4), (1,5), (1,6), (2,4), (2,5), (2,6), (3,4), (3,5), (3,6))
A little bit more explicit according to Nicolas:
In Scala you can use multiple generators in a single for-comprehension.
val xs = List(1,2,3)
val ys = List(4,5)
for {
x <- xs
y <- ys
} yield (x,y)
res0: List[(Int, Int)] = List((1,4), (1,5), (2,4), (2,5), (3,4), (3,5))
You can even evaluate in the comprehension.
for {
x <- xs
y <- ys
if (x + y == 6)
} yield (x,y)
res1: List[(Int, Int)] = List((1,5), (2,4))
Or make an assignment.
for {
x <- xs
y <- ys
val z = x + y
} yield (x,y,z)
res2: List[(Int,Int,Int)] = List((1,4,5), (1,5,6), (2,4,6), (2,5,7), (3,4,7), (3,5,8))