scala map function of map vs. list - scala

Snippet 1:
val l = List(1,2,43,4)
l.map(i => i *2)
Snippet 2:
val s = "dsadadaqer12"
val g = s.groupBy(c=>c)
g.map ( {case (c,s) => (c,s.length)})
In snippet #2, the syntax different than #1 , i.e. curly braces required -- why?
I thought the following would compile, but it does not:
g.map ( (c,s) => (c,s.length))
Can someone explain why?
Thanks

The difference between the two is - the latter uses Pattern Matching and the former doesn't.
The syntax g.map({case (c,s) => (c,s.length)}) is just syntax sugar for:
g.map(v => v match { case (c,s) => (c,s.length) })
Which means: we name the input argument of our anonymous function v, and then in the function body we match it to a tuple (c,s). Since this is so useful, Scala provides the shorthand version you used.
Of course - this doesn't really have anything to do with whether you use a Map or a List - consider all the following possibilities:
scala> val l = List(1,2,43,4)
l: List[Int] = List(1, 2, 43, 4)
scala> l.map({ case i => i*2 })
res0: List[Int] = List(2, 4, 86, 8)
scala> val l2 = List((1,2), (3,4))
l2: List[(Int, Int)] = List((1,2), (3,4))
scala> l2.map({ case (i, j) => i*j })
res1: List[Int] = List(2, 12)
scala> val g = Map(1 -> 2, 3 -> 4)
g: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
scala> g.map(t => t._1 * t._2)
res2: scala.collection.immutable.Iterable[Int] = List(2, 12)
Both Map and List can use both syntax options, depending mostly on what you actually want to do.

1- g.map{case (c,s) => (c,s.length)}
2- g.map((c,s) => (c,s.length))
The map method pulls a single argument, a 2-tuple, from the g collection. The 1st example compiles because the case statement uses pattern matching to extract the tuple's elements whereas the 2nd example doesn't and it won't compile. For that you'd have to do something like: g.map(t => (t._1, t._2.length))
As for the parenthesis vs. curly braces: braces have always been required for "partial functions," which is what that case statement is. You can use either braces or parens for anonymous functions (i.e. x => ...) although you are required to use braces if the function is more than a single line (i.e. has a carriage-return).
I read somewhere that this parens/braces distinction might be relaxed but I don't know if that's going to happen any time soon.

Related

How does map() on 'zipped' Lists work?

I am looking to calculate the scalar product of two lists. Let's say we have two Lists, l1 = List(1,2,3) and l2 = List(4,5,6), the result should be List(4,10,18)
The code below works:
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map(xy => xy._1*xy._2)
}
However, the following fails to compile, and says Cannot resolve reference map with such signature :
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map((x:Int,y:Int) => x*y)
}
This zip() would return a list of Int pairs, and the above map is also taking a function which takes an Int pair.
Could someone point out why does the second variant fail in this case?
Your second example fails because you provide a function with 2 parameters to the map, while map takes a function with 1 parameter.
Have a look, here's a (simplified) signature of the map function:
def map[B, That](f: A => B): That
The function f is the one that you have to pass to do the conversion. As you can see, it has type A => B, i.e. accept a single parameter.
Now take a look at the (simplified) zip function signature:
def zip [B](that : List[B]) : List[(A, B)]
It actually produces a list whose members are tuples. Tuple of 2 elements looks like this: (A, B). When you call map on the list of tuples, you have to provide the function f that takes a tuple of 2 elements as a parameter, exactly like you do in your first example.
Since it's inconvenient to work with tuples directly, you could extract values of tuple's members to a separate variables using pattern matching.
Here's an REPL session to illustrate this.
scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)
scala> List(2, 3, 4)
res1: List[Int] = List(2, 3, 4)
scala> res0 zip res1
res2: List[(Int, Int)] = List((1,2), (2,3), (3,4))
Here's how you do a standard tuple values extraction with pattern matching:
scala> res2.map(t => t match {
| case (x, y) => x * y
| })
res3: List[Int] = List(2, 6, 12)
It's important to note here that pattern matching expects a partial function as an argument. I.e. the following expression is actually a partial function:
{
case (x, y) => x * y
}
The partial function has its own type in Scala: trait PartialFunction[-A, +B] extends (A) => B, and you could read more about it, for example, here.
Partial function is a normal function, since it extends (A) => B, and that's why you can pass a partial function to the map call:
scala> res2.map { case (x, y) => x * y }
res4: List[Int] = List(2, 6, 12)
You actually use special Scala syntax here, that allows for functions invocations (map in our case) without parentheses around its parameters. You can alternatively write this with parentheses as follows:
scala> res2.map ({ case (x, y) => x * y })
res5: List[Int] = List(2, 6, 12)
There's no difference between the 2 last calls at all.
The fact that you don't have to declare a parameter of anonymous function you pass to the map before you do pattern matching on it, is actually Scala's syntactic sugar. When you call res2.map { case (x, y) => x * y }, what's really going on is pattern matching with partial function.
Hope this helps.
you need something like:
def scalarProduct(l1 : List[Int], l2 : List[Int]):List[Int] = {
val l3 = l1 zip(l2); l3 map{ case (x:Int,y:Int) => x*y}
}
You can have a look at this link to help you with this type of problems.

What is the inverse of intercalate, and how to implement it?

This question discusses how to interleave two lists in an alternating fashion, i.e. intercalate them.
What is the inverse of "intercalate" called?
Is there an idiomatic way to implement this in Scala?
The topic is discussed on this Haskell IRC session.
Possibilities include "deintercalate", "extracalate", "ubercalate", "outercalate", and "chocolate" ;-)
Assuming we go for "extracalate", it can be implemented as a fold:
def extracalate[A](a: List[A]) =
a.foldRight((List[A](), List[A]())){ case (b, (a1,a2)) => (b :: a2, a1) }
For example:
val mary = List("Mary", "had", "a", "little", "lamb")
extracalate(mary)
//> (List(Mary, a, lamb),List(had, little)
Note that the original lists can only be reconstructed if either:
the input lists were the same length, or
the first list was 1 longer than the second list
The second case actually turns out to be useful for the geohashing algorithm, where the latitude bits and longitude bits are intercalated, but there may be an odd number of bits.
Note also that the definition of intercalate in the linked question is different from the definition in the Haskell libraries, which intersperses a list in between a list of lists!
Update: As for any fold, we supply a starting value and a function to apply to each value of the input list. This function modifies the starting value and passes it to the next step of the fold.
Here, we start with a pair of empty output lists: (List[A](), List[A]())
Then for each element in the input list, we add it onto the front of one of the output lists using cons ::. However, we also swap the order of the two output lists , each time the function is invoked; (a1, a2) becomes (b :: a2, a1). This divides the input list between the two output lists in alternating fashion. Because it's a right fold, we start at the end of the input list, which is necessary to get each output list in the correct order. Proceeding from the starting value to the final value, we would get:
([], [])
([lamb], [])
([little],[lamb])
([a, lamb],[little])
([had, little],[a, lamb])
([Mary, a, lamb],[had, little])
Also, using standard methods
val mary = List("Mary", "had", "a", "little", "lamb")
//> mary : List[String] = List(Mary, had, a, little, lamb)
val (f, s) = mary.zipWithIndex.partition(_._2 % 2 == 0)
//> f : List[(String, Int)] = List((Mary,0), (a,2), (lamb,4))
//| s : List[(String, Int)] = List((had,1), (little,3))
(f.unzip._1, s.unzip._1)
//> res0: (List[String], List[String]) = (List(Mary, a, lamb),List(had, little))
Not really recommending it, though, the fold will beat it hands down on performance
Skinning the cat another way
val g = mary.zipWithIndex.groupBy(_._2 % 2)
//> g : scala.collection.immutable.Map[Int,List[(String, Int)]] = Map(1 -> List
//| ((had,1), (little,3)), 0 -> List((Mary,0), (a,2), (lamb,4)))
(g(0).unzip._1, g(1).unzip._1)
//> res1: (List[String], List[String]) = (List(Mary, a, lamb),List(had, little))
Also going to be slow
I think it's inferior to #DNA's answer as it's more code and it requires passing through the list twice.
scala> list
res27: List[Int] = List(1, 2, 3, 4, 5)
scala> val first = list.zipWithIndex.filter( x => x._1 % 2 == 1).map(x => x._2)
first: List[Int] = List(0, 2, 4)
scala> val second = list.zipWithIndex.filter( x => x._1 % 2 == 0).map(x => x._2)
second: List[Int] = List(1, 3)
scala> (first, second)
res28: (List[Int], List[Int]) = (List(0, 2, 4),List(1, 3))

How can I get a sum of arrays of tuples in scala

I have a simple array of tuples
val arr = Array((1,2), (3,4),(5,6),(7,8),(9,10))
I wish to get (1+3+5+7+9, 2+4+6+8+10) tuple as the answer
What is the best way to get the sum as tuples, similar to regular arrays. I tried
val res = arr.foldLeft(0,0)(_ + _)
This does not work.
Sorry about not writing the context. I was using it in scalding with algebird. Algebird allows sums of tuples and I assumed this would work. That was my mistake.
There is no such thing as Tuple addition, so that can't work. You would have to operate on each ordinate of the Tuple:
val res = arr.foldLeft(0,0){ case (sum, next) => (sum._1 + next._1, sum._2 + next._2) }
res: (Int, Int) = (25,30)
This should work nicely:
arr.foldLeft((0,0)){ case ((a0,b0),(a1,b1)) => (a0+a1,b0+b1) }
Addition isn't defined for tuples.
Use scalaz, which defines a tuple as a semigroup, allowing you to use the append operator |+|
import scalaz._
import Scalaz._
arr.fold((0,0))(_ |+| _)
Yet another alternative
val (a, b) = arr.unzip
//> a : Array[Int] = Array(1, 3, 5, 7, 9)
//| b : Array[Int] = Array(2, 4, 6, 8, 10)
(a.sum, b.sum)
//> res0: (Int, Int) = (25,30)

What does map in Scala do

Can somebody explain what does map on Lists exactly do in Scala?
For example the following line of code:
map(row => row(column))
map does transformation by applying a function to each element, your example is hard to read without more code, simple example is
scala> val l = List(1,2,3)
scala> l.map( x => x*2 )
res1: List[Int] = List(2, 4, 6)

Rules on using a case statement to destruct a tuple in Scala

I have the following code:
val xs = List(('a', 1), ('a', 2), ('b', 3), ('b', 4))
I want to transform this into a Map. e.g. Map('a' -> Seq(1,2), 'b' -> Seq(3,4)). So I proceed to write the transformation:
xs.groupBy(_._1) map {
case (k, v) => (k, v.map(_._2))
}
Why does the brace after the map need to be a {. When I started, I assumed I could do the following:
xs.groupBy(_._1).map(case (k, v) => (k, v.map(_._2)))
But that doesn't compile.
Because .map method accepts a function
What you've actually written is
map({
case (k, v) => (k, v.map(_._2))
})
and the { case (k, v) => (k, v.map(_._2)) } is a shortcut definition for pattern matching anonymous function (SLS, ยง8.5) which is one of the function kinds:
val isOdd: PartialFunction[Int, String] = {
case x if x % 2 == 1 => x+" is odd"
}
val upcastedIsOdd: Function[Int, String] = {
case x if x % 2 == 1 => x+" is odd"
}
You cannot ommit curly braces (so you'll loose partial function and patten matching nicity) but you can skip plain braces (and still retain partial function) just like in the snippet below:
scala> List(1,2,3).take(1)
//res0: List[Int] = List(1)
scala> List(1,2,3) take 1
//res1: List[Int] = List(1)
It seems the real question here is when can one use parenthesis ( in place of braces { to represent an anonymous function. I recommend having a look at Daniel Sobral's answer to the question: What is the formal difference in Scala between braces and parentheses, and when should they be used?