2

From this link showing some Scala examples:
http://spark.apache.org/docs/latest/mllib-collaborative-filtering.html

what is the difference between map{} and map()?

val ratings = data.map(_.split(',') match { case Array(user, item, rate) =>
  Rating(user.toInt, item.toInt, rate.toDouble)
})

val usersProducts = ratings.map { case Rating(user, product, rate) =>
  (user, product)
}
SusanW
  • 1,550
  • 1
  • 12
  • 22

2 Answers2

6

map is a method which accepts a function as an argument. So map customarily is called just like methods get called: map(aFunction). However, Scala provides a lot of flexibility / shorthands in its syntax:

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

//An ordinary method call. The braces just evaluate to an anonymous function
val a = list.map({ case (a, b) => a + b }) // List(3,7)  


// Now lets define a non anonymous function of the same type as above:
def  func(x: (Int,Int)) = x match {case (a,b) => a + b}

// Scala allows this readable "infix notation" for single parameter methods 
val a = list map func // List(3,7)

//Now to the main point you asked, this syntax uses the same readable form as above 
//but uses an anonymous function.  
val a = list map {case (a,b) => a + b} // List(3,7)
Samar
  • 2,091
  • 1
  • 15
  • 18
3
val a = list.map(_.split(','))

// the above is a shorthand for
val a = list.map({ case i => i.split(',') })

// Now lets consider this
val a = list.map { case (a, b) => a + b }

// or this
val a = list map { case (a, b) => a + b }

// some people like the above ways of writing
// because they consider of less brackets as cleaner code.
// but the above two are another way to write
val a = list.map({ case (a, b) => a + b })

The thing to understand here is that in Scala you can use spaces instead of . to access instance methods.

So basically,

// lets say you have a class A
case class A(i: Int) {

  def merged[B](b: B): String = i.toString + " :: " + b.toString

}

//Now, lets say you have an instance of A
val a = A(5)
// and an instance of String
val s: String = "abcd"

// Now, if you write
val merged = a merged s
// it is syntactic sugar for
val merged = a.merged(s)

Similarly, List[A] has a method map[B](f: A => B): List[B].

val list = List[Int](1, 2, 3)

// so when you write
val list2 = list map { case i => i + 1}

// its syntactic sugar for,
val list2 = list.map({ case i => i + 1 })

// There is a lot going on here
// if we were to do everything step by step

// first you are creating a partial function
val pf: PartialFunction[Int, Int] = { case i => i + 1 }

// Now, PartialFunction[Int, Int] is a subtype of Int => Int
// so we can refer to it as a Int => Int
val f: Int => Int = pf

// Now we pass it as an argument to map
val list2 = list.map(f)
sarveshseri
  • 13,738
  • 28
  • 47
  • nicely done, thank you – Christian Yonathan S. Aug 18 '16 at 05:58
  • 2
    No, the first is not a shorthand for the second. The second doesn't even compile. It should be `a => a.split(',')`. – Alexey Romanov Aug 18 '16 at 06:28
  • 2
    There's even more to what Alexey said. `{}` indicates that an anonymous function body will be provided as input and has almost nothing to do with shorthands. It is not bound to the `map` method or even higher order functions in general. – sebszyller Aug 18 '16 at 08:28
  • @sebszyller do you understand that in scala you can use spaces instead of `.` to access instance method. So basically any expression `a abc b` where `b` is an instance of some class `B` and `a` is an instance of class `A` having a method `abc[B](b: B)` is actually syntactic sugar for `a.abc(b)`. – sarveshseri Aug 19 '16 at 14:35
  • Of course, but what does have to do with `{}` and `()`? – sebszyller Aug 19 '16 at 14:37
  • @sebszyller Similarly in case of `a map { case i => i.toString }`. it is actually syntactic sugar for `a.map({ case i => i.toString })` where `{ case i => i.toString }` is a `PartialFunction[Int, String]` which is a subtype of `Int => String` and hence is acceptable by `List[Int].map` as it has a signature of `List[A].map[B](f: A => B)` which in this case becomes `List[Int].map[String](f: Int => String)`. – sarveshseri Aug 19 '16 at 14:46
  • That's correct. Though my point is, that if you pass a parameter that is a function body (that is an anonymous function) you have to use `{}`. That's why this doesn't work `val l1 = List(1, 2, 3)` `val l2 = l1 map(i => val j = 3; i * j)` and this does `val l3 = l1 map { i => val j = 3; i * j }` or `def myFunc(x: Int): x` needs `{}` in `val i = myFunc { val j = 1; val k = 2; j + k }` No need, to take it so personally. Regards :) – sebszyller Aug 19 '16 at 15:06
  • This `SimpleExpr ::= SimpleExpr1 ArgumentExprs` and `ArgumentExprs ::= [nl] BlockExpr` thing in functional applicant part of Scala language specification is the syntactic sugar that I am talking about. http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#function-applications . – sarveshseri Aug 19 '16 at 16:51