This question already has answers here:
What is the formal difference in Scala between braces and parentheses, and when should they be used?
(9 answers)
Closed 6 years ago.
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)
}
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)
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)
Related
I am still learning the basics of Scala, therefore I am asking for your understanding. Is it any possible way to use fold method to print only names beginning with "A"
Object Scala {
val names: List[String] = List("Adam", "Mick", "Ann");
def main(args: Array[String]) {
println(names.foldLeft("my list of items starting with A: ")(_+_));
}
}
}
Have a look at the signature of foldLeft
def foldLeft[B](z: B)(op: (B, A) => B): B
where
z is the initial value
op is a function taking two arguments, namely accumulated result so far B, and the next element to be processed A
returns the accumulated result B
Now consider this concrete implementation
val names: List[String] = List("Adam", "Mick", "Ann")
val predicate: String => Boolean = str => str.startsWith("A")
names.foldLeft(List.empty[String]) { (accumulated: List[String], next: String) =>
if (predicate(next)) accumulated.prepended(next) else accumulated
}
here
z = List.empty[String]
op = (accumulated: List[String], next: String) => if (predicate(next)) accumulated.prepended(next) else accumulated
Usually we would write this inlined and rely on type inference so we do not have two write out full types all the time, so it becomes
names.foldLeft(List.empty[String]) { (acc, next) =>
if (next.startsWith("A")) next :: acc else acc
}
// val res1: List[String] = List(Ann, Adam)
On of the key ideas when working with List is to always prepend an element instead of append
names.foldLeft(List.empty[String]) { (accumulated: List[String], next: String) =>
if (predicate(next)) accumulated.appended(next) else accumulated
}
because prepending is much more efficient. However note how this makes the accumulated result in reverse order, so
List(Ann, Adam)
instead of perhaps required
List(Adam, Ann)
so often-times we perform one last traversal by calling reverse like so
names.foldLeft(List.empty[String]) { (acc, next) =>
if (next.startsWith("A")) next :: acc else acc
}.reverse
// val res1: List[String] = List(Adam, Ann)
The answer from #Mario Galic is a good one and should be accepted. (It's the polite thing to do).
Here's a slightly different way to filter for starts-with-A strings.
val names: List[String] = List("Adam", "Mick", "Ann")
println(names.foldLeft("my list of items starting with A: "){
case (acc, s"A$nme") => acc + s"A$nme "
case (acc, _ ) => acc
})
//output: "my list of items starting with A: Adam Ann"
I would like to achieve something akin to the strategy pattern in scala without resorting to pattern matching with a long list of case statements. Here is roughly what I have in mind:
trait HandlerTrait {
def handlerA(...): Unit
def handlerB(...): Unit
}
SomeClass1 extends HandlerTrait {
override def handlerA(...) {...}
override def handlerB(...) {...}
}
SomeClass2 extends HandlerTrait {
override def handlerA(...) {...}
override def handlerB(...) {...}
}
object MyApp extends App {
// 1. define bindings for these implementations
val myBindings = Map(x -> someClass1, y -> someClass2)
// 2. Such that implementation of someMethod targeting handlerA implementations could look like this:
def someMethod(object: ObjectType): Unit = {
myBindings.get(object.x) match {
case Some(entry) => entry.handlerA(object)
case None => ()
}
}
}
A few more things:
I don't know how many SomeClassXXX I will have. I will add as needed
to provide customizations on how to handle A/B/C ...
Given a key, I want to dispatch to the correct class and execute the targeted handler.
Is there a better more concise way of achieving this in scala?
I think one way to reduce boilerplate is to use type system rather than inheritance. For instance, if your handler is of type T => Unit then any function that satisfies this type can be a handler, there is no need to officially declare HandlerTrait and even someMethod.
Whether to use a Map or cases to map from a key to a handler is up to you. Both can be extended to handle new cases.
Here is an example to sum up what I'm proposing:
val currentlyDefinedStrategies: PartialFunction[String, Unit] = {
case "1" => println(1)
case "2" => println(2)
}
val newStrategies: PartialFunction[String, Unit] = {
case "3" => println(3)
}
val defaultStrategy: PartialFunction[String, Unit] = {
case _ => println("default")
}
And usage:
scala> currentlyDefinedStrategies("1")
1
scala> currentlyDefinedStrategies("3")
scala.MatchError: 3 (of class java.lang.String) ...
scala> currentlyDefinedStrategies.orElse(newStrategies)("3")
3
scala> currentlyDefinedStrategies.orElse(newStrategies)("4")
scala.MatchError: 4 (of class java.lang.String)
scala> currentlyDefinedStrategies.orElse(newStrategies).orElse(defaultStrategy)("4")
default
You can achieve similar pattern with Map or using other FP techniques. The main point is to keep the most relevant code and get rid of boilerplate. Of course, HandlerTrait might be useful to you for structuring your code and thinking in terms of classes rather than functions, but the idea is the same.
See also: https://pavelfatin.com/design-patterns-in-scala/#strategy
The above example is a bit simplified and you actually want to pass parameters to handler (println in our case). Here is how:
val currentlyDefinedStrategies: Int => PartialFunction[String, Unit] = (x) => {
case "1" => println("1: " + x)
case "2" => println("2: " + x)
case _ => println("default: " + x)
}
You can fix the argument without choosing a strategy:
scala> val noStrategy = currentlyDefinedStrategies(1)
noStrategy: PartialFunction[String,Unit] = <function1>
... and provide strategy afterwards:
scala> noStrategy("1")
1: 1
Or apply the strategy right away:
scala> currentlyDefinedStrategies(1)("1")
1: 1
You can also decide on your strategy first and then pass an argument:
val currentlyDefinedStrategies: PartialFunction[String, Int => Unit] = {
case "1" => x => println("1: " + x)
case "2" => x => println("2: " + x)
case _ => x => println("default: " + x)
}
scala> val handlerWithChosenStrategy = currentlyDefinedStrategies("1")
handlerWithChosenStrategy: Int => Unit = $anonfun$1$$Lambda$1374/666224848#59a9f3eb
scala> handlerWithChosenStrategy(1)
1: 1
I think the point is that FP is so rich and flexible that strategy pattern is really not a thing. It's basically just some function type that suits your convenience like type Strategy[T, -A, +B] = PartialFunction[T, A => B]. Example:
scala> type Strategy[T, -A, +B] = PartialFunction[T, A => B]
defined type alias Strategy
val currentlyDefinedStrategies: Strategy[String, Int, Unit] = {
case "1" => x => println("1: " + x)
case "2" => x => println("2: " + x)
case _ => x => println("default: " + x)
}
currentlyDefinedStrategies: Strategy[String,Int,Unit] = <function1>
scala> currentlyDefinedStrategies("1")(1)
1: 1
A more advanced concept would be an Expression Problem (here) where you need to extend both the operations you can do on types as well as adding new types.
I want to update a sequence in Scala, I have this code :
def update(userId: Long): Either[String, Int] = {
Logins.findByUserId(userId) map {
logins: Login => update(login.id,
Seq(NamedParameter("random_date", "prefix-" + logins.randomDate)))
} match {
case sequence : Seq(Nil, Int) => sequence.foldLeft(Right(_) + Right(_))
case _ => Left("error.logins.update")
}
}
Where findByUserId returns a Seq[Logins] and update returns Either[String, Int] where Int is the number of updated rows,
and String would be the description of the error.
What I want to achieve is to return an String if while updating the list an error happenes or an Int with the total number of updated rows.
The code is not working, I think I should do something different in the match, I don't know how I can check if every element in the Seq of Eithers is a Right value.
If you are open to using Scalaz or Cats you can use traverse. An example using Scalaz :
import scalaz.std.either._
import scalaz.std.list._
import scalaz.syntax.traverse._
val logins = Seq(1, 2, 3)
val updateRight: Int => Either[String, Int] = Right(_)
val updateLeft: Int => Either[String, Int] = _ => Left("kaboom")
logins.toList.traverseU(updateLeft).map(_.sum) // Left(kaboom)
logins.toList.traverseU(updateRight).map(_.sum) // Right(6)
Traversing over the logins gives us a Either[String, List[Int]], if we get the sum of the List we get the wanted Either[String, Int].
We use toList because there is no Traverse instance for Seq.
traverse is a combination of map and sequence.
We use traverseU instead of traverse because it infers some of the types for us (otherwise we should have introduced a type alias or a type lambda).
Because we imported scalaz.std.either._ we can use map directly without using a right projection (.right.map).
You shouldn't really use a fold if you want to exit early. A better solution would be to recursively iterate over the list, updating and counting successes, then return the error when you encounter one.
Here's a little example function that shows the technique. You would probably want to modify this to do the update on each login instead of just counting.
val noErrors = List[Either[String,Int]](Right(10), Right(12))
val hasError = List[Either[String,Int]](Right(10), Left("oops"), Right(12))
def checkList(l: List[Either[String,Int]], goodCount: Int): Either[String, Int] = {
l match {
case Left(err) :: xs =>
Left(err)
case Right(_) :: xs =>
checkList(xs, (goodCount + 1))
case Nil =>
Right(goodCount)
}
}
val r1 = checkList(noErrors, 0)
val r2 = checkList(hasError, 0)
// r1: Either[String,Int] = Right(2)
// r2: Either[String,Int] = Left(oops)
You want to stop as soon as an update fails, don't you?
That means that you want to be doing your matching inside the map, not outside. Try is actually a more suitable construct for this purpose, than Either. Something like this, perhaps:
def update(userId: Long): Either[String, Int] = Try {
Logins.findByUserId(userId) map { login =>
update(login.id, whatever) match {
case Right(x) => x
case Left(s) => throw new Exception(s)
}
}.sum
}
.map { n => Right(n) }
.recover { case ex => Left(ex.getMessage) }
BTW, a not-too-widely-known fact about scala is that putting a return statement inside a lambda, actually returns from the enclosing method. So, another, somewhat shorter way to write this would be like this:
def update(userId: Long): Either[String, Int] =
Logins.findByUserId(userId).foldLeft(Right(0)) { (sum,login) =>
update(login.id, whatever) match {
case Right(x) => Right(sum.right + x)
case error#Left(s) => return error
}
}
Also, why in the world does findUserById return a sequence???
Suppose I have 2 methods:
def a(s: String) = s + "..."
def b(s: String) = s + ",,,"
And I want to create 3rd method which will call both methods:
def c (s: String) = a(b(s))
How I can do it in idiomatic Scala way?
I think it's better to aggregate this functions into some List and then sequentially apply them:
List(a_, b_)
I think it's better to aggregate this functions into some List and
then sequentially apply them.
You get some help by specifying an expected type:
scala> val fs: List[String => String] = List(a,b)
fs: List[String => String] = List(<function1>, <function1>)
scala> fs.foldLeft("something")((s,f) => f(s))
res0: String = something...,,,
Here is how you can combine a set of functions into one:
// a() and b() are as defined in the question
// the following is equivalent to newfunc(x) = b(a(x))
val newFunc: String => String = List( a _, b _).reduce( _ andThen _ )
You can even create a generic function to combine them:
def functionChaining[A]( functions: A => A *): A => A = functions.reduce( _ andThen _ )
or using foldLeft:
def functionChaining[A]( functions: A => A *): A => A = functions.foldLeft( (x:A) => x )( _ andThen _ )
Here is an example of how to use this on the REPL:
scala> val newFunc: String => String = functionChaining( (x:String) => x + "---", (x:String) => x * 4)
scala> newFunc("|")
res12: String = |---|---|---|---
Many answers use andThen, but that will be give you
b(a(s))
Given that you want
a(b(s))
compose is the way to go (well, that or reversing the list, but what's the point?)
def c(s: String) = List[String => String](a, b).reduce(_ compose _)(s)
// or alternatively
def c(s: String) = List(a _, b _).reduce(_ compose _)(s)
As a result
c("foo") // foo,,,...
Now, speaking of what's idiomatic, I believe that
a(b(s))
is more idiomatic and readable than
List(a _, b _).reduce(_ compose _)(s)
This clearly depends on the number of functions you're composing. If you were to have
a(b(c(d(e(f(g(h(s))))))))
then
List[String => String](a, b, c, d, e, f, g, h).reduce(_ compose _)(s)
is probably neater and more idiomatic as well.
If you really think you need to do this:
val c = a _ andThen b
// (The signature is:)
val c:(String)=>String = a _ andThen b
or, more obviously:
def d(s:String) = a _ andThen b
If chained application is preferred then the below works. Caveats - Implicit syntax is a bit ugly; This being a structural type uses reflection.
object string {
implicit def aPimp(s: String) = new {
def a = "(a- " + s + " -a)"
}
implicit def bPimp(s: String) = new {
def b = "(b- " + s + " -b)"
}
}
scala> import string._
scala> "xyz".a.b
res0: String = (b- (a- xyz -a) -b)
scala> "xyz".b.a
res1: String = (a- (b- xyz -b) -a)
In my opinion, if not for the ugly syntax, this would be idiomatic scala.
Starting my first project with Scala: a poker framework.
So I have the following class
class Card(rank1: CardRank, suit1: Suit){
val rank = rank1
val suit = suit1
}
And a Utils object which contains two methods that do almost the same thing: they count number of cards for each rank or suit
def getSuits(cards: List[Card]) = {
def getSuits(cards: List[Card], suits: Map[Suit, Int]): (Map[Suit, Int]) = {
if (cards.isEmpty)
return suits
val suit = cards.head.suit
val value = if (suits.contains(suit)) suits(suit) + 1 else 1
getSuits(cards.tail, suits + (suit -> value))
}
getSuits(cards, Map[Suit, Int]())
}
def getRanks(cards: List[Card]): Map[CardRank, Int] = {
def getRanks(cards: List[Card], ranks: Map[CardRank, Int]): Map[CardRank, Int] = {
if (cards isEmpty)
return ranks
val rank = cards.head.rank
val value = if (ranks.contains(rank)) ranks(rank) + 1 else 1
getRanks(cards.tail, ranks + (rank -> value))
}
getRanks(cards, Map[CardRank, Int]())
}
Is there any way I can "unify" these two methods in a single one with "field/method-as-parameter"?
Thanks
Yes, that would require high order function (that is, function that takes function as parameter) and type parameters/genericity
def groupAndCount[A,B](elements: List[A], toCount: A => B): Map[B, Int] = {
// could be your implementation, just note key instead of suit/rank
// and change val suit = ... or val rank = ...
// to val key = toCount(card.head)
}
then
def getSuits(cards: List[Card]) = groupAndCount(cards, {c : Card => c.suit})
def getRanks(cards: List[Card]) = groupAndCount(cards, {c: Card => c.rank})
You do not need type parameter A, you could force the method to work only on Card, but that would be a pity.
For extra credit, you can use two parameter lists, and have
def groupAndCount[A,B](elements: List[A])(toCount: A => B): Map[B, Int] = ...
that is a little peculiarity of scala with type inference, if you do with two parameters lists, you will not need to type the card argument when defining the function :
def getSuits(cards: List[Card]) = groupAndCount(cards)(c => c.suit)
or just
def getSuits(cards: List[Card] = groupAndCount(cards)(_.suit)
Of course, the library can help you with the implementation
def groupAndCount[A,B](l: List[A])(toCount: A => B) : Map[A,B] =
l.groupBy(toCount).map{case (k, elems) => (k, elems.length)}
although a hand made implementation might be marginally faster.
A minor note, Card should be declared a case class :
case class Card(rank: CardRank, suit: Suit)
// declaration done, nothing else needed