Multi-Assignment based on Collection - scala

Edit
originally the question was "Collection to Tuple" as I assumed I needed a tuple in order to do variable multi-assignment. It turns out that one can do variable multi-assignment directly on collections. Retitled the question accordingly.
Original
Have a simple Seq[String] derived from a regex that I would like to convert to a Tuple.
What's the most direct way to do so?
I currently have:
val(clazz, date) = captures match {
case x: Seq[String] => (x(0), x(1))
}
Which is ok, but my routing layer has a bunch of regex matched routes that I'll be doing val(a,b,c) multi-assignment on (the capture group is always known since the route is not processed if regex does not match). Would be nice to have a leaner solution than match { case.. => ..}
What's the shortest 1-liner to convert collections to tuples in Scala?

This is not an answer to the question but might solve the problem in a different way.
You know you can match a xs: List[String] like so:
val a :: b :: c :: _ = xs
This assigns the first three elements of the list to a,b,c? You can match other things like Seq in the declaration of a val just like inside a case statement. Be sure you take care of matching errors:
Catching MatchError at val initialisation with pattern matching in Scala?

You can make it slightly nicer using |> operator from Scalaz.
scala> val captures = Vector("Hello", "World")
captures: scala.collection.immutable.Vector[java.lang.String] = Vector(Hello, World)
scala> val (a, b) = captures |> { x => (x(0), x(1)) }
a: java.lang.String = Hello
b: java.lang.String = World
If you don't want to use Scalaz, you can define |> yourself as shown below:
scala> class AW[A](a: A) {
| def |>[B](f: A => B): B = f(a)
| }
defined class AW
scala> implicit def aW[A](a: A): AW[A] = new AW(a)
aW: [A](a: A)AW[A]
EDIT:
Or, something like #ziggystar's suggestion:
scala> val Vector(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World
You can make it more concise as shown below:
scala> val S = Seq
S: scala.collection.Seq.type = scala.collection.Seq$#157e63a
scala> val S(a, b) = captures
a: java.lang.String = Hello
b: java.lang.String = World

As proposed by #ziggystar in comments you can do something like:
val (clazz, date) = { val a::b::_ = capture; (a, b)}
or
val (clazz, date) = (capture(0), capture(1))
If you verified the type of the list before it is OK, but take care of the length of the Seq because the code will run even if the list is of size 0 or 1.

Your question is originally specifically about assigning the individual capturing groups in a regex, which already allow you to assign from them directly:
scala> val regex = """(\d*)-(\d*)-(\d*)""".r
regex: scala.util.matching.Regex = (\d*)-(\d*)-(\d*)
scala> val regex(a, b, c) = "29-1-2012"
d: String = 29
m: String = 1
y: String = 2012
obviously you can use these in a case as well:
scala> "29-1-2012" match { case regex(d, m, y) => (y, m, d) }
res16: (String, String, String) = (2012,1,29)
and then group these as required.

Seqs to tuple
To perform multi-assignment from a Seq, what about the following?
val Seq(clazz, date) = captures
As you see, no need to restrict to Lists; this code will throw a MatchError if the length does not match (in your case, that's good because it means that you made a mistake). You can then add
(clazz, date)
to recreate the tuple.
Tuples from matches
However, Jed Wesley-Smith posted a solution which avoids this problem and solves the original question better. In particular, in your solution you have a Seq whose length is not specified, so if you make a mistake the compiler won't tell you; with tuples instead the compiler can help you (even if it can't check against the regexp).

Related

What is the real world example of Scala's Partially applied Function

I am new to Scala (Functional Programming). I am reading the book 'Functional Programming in Scala'. It was an exercise in which we need to define a partially applied function
def partial1 [A, B, C] (a: A, f: (A, B) => C): B => C = {
(b: B) => f(a, b)
}
I was wondering what is a real world use of this function? I tried to read different blogs to find an example, but couldn't find a useful example.
(Relevant to your question before you edited it) Let's start with terminology. PartialFunction is trait in scala that says that your function might not process all possible variations of the input:
val partialFunction: PartialFunction[Int, Int] = {
case 1 => 1
case 2 => 2
}
scala> partialFunction(1)
res43: Int = 1
scala> partialFunction(3)
scala.MatchError: 3 (of class java.lang.Integer)
It's completely unrelated to your example, which is a partial application - the article provided basically shows real-world example with email filtering.
About partial application.
Sometimes you might have a function with several parameters, let's say:
def sendMail(recipient: String, subject: String, body: String) = println(s"To: $recipient\n Subj: $subject\n Body: $body")
This function might be a part of the API, so you might not be able to change it. Now, let's say you need to send a same email to many different recipients:
object Spam{
val subject = "Hello!"
val body = "World!"
def spam(recipient: String) = sendMail(recipient, subject, body)
}
scala> Spam.spam("aaa#aa")
To: aaa#aa
Subj: Hello!
Body: World!
Another way to do that is to generate a function per subject/body, so to make it customizable:
def spammer(subject: String, body: String): String => Unit = (recipient: String) => {
sendMail(recipient, subject, body)
}
val spam1 = spammer("Hello", "World!")
spam1("emai#email.com")
It's roughly equivalent to OOP's:
class Spammer(subject: String, body: String){
def apply(recipient: String) = sendMail(recipient, subject, body)
}
val spam1 = new Spammer("Hello", "World!")
spam1("emai#email.com")
The difference is that partial application is able to deal more easily with complex cases and also has additional syntax sugar:
val spam1 = sendMail(_, "Hello", "World!")
spam1("emai#email.com")
So in simple cases you don't even need to define your own wrapper.
Returning to your more sophisticated example, you could use it this way:
scala> val incrementInt = partial1[Int, Int, Int](1, _ + _)
incrementInt: Int => Int = $$Lambda$1258/21635151#18ca65ea
scala> incrementInt(2)
res47: Int = 3
scala> val incrementList = partial1[List[Int], List[Int], List[Int]](List(0), _ ++ _)
incrementList: List[Int] => List[Int] = $$Lambda$1258/21635151#79f8af90
scala> incrementList(List(0))
res49: List[Int] = List(0, 0)
scala> incrementList(List(0, 0))
res50: List[Int] = List(0, 0, 0)
Basically abstract over addition (A, B) = C of some fixed abstract element A to unknown element B. In the example above it's addition over integers, and addition over lists of zeros. You can imagine more practical example like merging two json's with some fixed pattern and so on.
You might think of partail1 as providing a unified interface to all those cases.

How to transform Array(e1, e2) into (e1, e2) using Scala 2.11.6 API only? [duplicate]

This question already has answers here:
How to convert an Array to a Tuple?
(4 answers)
Closed 7 years ago.
Given:
scala> val ss = "hello_world".split("_")
ss: Array[String] = Array(hello, world)
How to turn ss into a tuple (hello, world) with a function of Array (on ss)? I'm thinking about a function so the above snippet would end up as "hello_world".split("_").to[Tuple2] or alike.
Is it possible using Scala 2.11.6 API only?
The shortest I could come up with:
scala> "hello_world" split("_") match { case Array(f, s) => (f, s) }
res0: (String, String) = (hello,world)
Of course it will throw for other non Tuple2 cases. You can have this to avoid exceptons:
scala> "hello_world" split("_") match { case Array(f, s) => Some(f, s); case _ => None }
res1: Option[(String, String)] = Some((hello,world))
Or with implicits:
scala> implicit class ArrayTupple[T](val a: Array[T]) { def pair = a match { case Array(f, s) => (f, s) } }
defined class ArrayTupple
scala> val ss = "hello_world".split("_")
ss: Array[String] = Array(hello, world)
scala> ss.pair
res0: (String, String) = (hello,world)
I'm still not very happy with the solution. Seems like you have to either write out all possible cases up to Tuple22 to make more generic method like to[Tuple22] or maybe use macros.
Unfortunatelly there's no function, that can convert Array of N elements (of course N <= 22) to TupleN. There is a proposed change to Scala API[1] to add :+ and +: methods to a tuple, but it has a low priority. What people do in their projects is basically summed up in an SO question [2].
If you do what they propose, and create classes from TupleOps2 to Tuple22` it still wouldn't be possible. Look at the code below:
def array2Tuple[T](array: Array[T]): TupleN = {
if(array.length == 2)
(array(0), array(1))
else
array(0) +: array2Tuple(array.drop(1))
}
It is still not possible, to deduce N in TupleN return type. The problem here is of course with the size of the array vs. size of Tuple. Size of array is contained inside the object, while size of Tuple is contained in a type name.
References:
[1] https://issues.scala-lang.org/browse/SI-7305
[2] How to append or prepend an element to a tuple in Scala
I don't think you can do better than
"size_known".split("_") match { case Array(a, b) => (a, b) }
or
Some("size_is_unknown".split("_")) collect { case Array(a, b) => (a, b) }
without reinventing some features of Shapeless, that makes it easy

Getting Value of Either

Besides using match, is there an Option-like way to getOrElse the actual content of the Right or Left value?
scala> val x: Either[String,Int] = Right(5)
scala> val a: String = x match {
case Right(x) => x.toString
case Left(x) => "left"
}
a: String = 5
Nicolas Rinaudo's answer regarding calling getOrElse on either the left or right projection is probably the closest to Option.getOrElse.
Alternatively, you can fold the either:
scala> val x: Either[String,Int] = Right(5)
x: Either[String,Int] = Right(5)
scala> val a: String = x.fold(l => "left", r => r.toString)
a: String = 5
As l is not used in the above fold, you could also write x.fold(_ => "left", r => r.toString)
Edit:
Actually, you can literally have Option.getOrElse by calling toOption on the left or right projection of the either, eg,
scala> val o: Option[Int] = x.right.toOption
o: Option[Int] = Some(5)
scala> val a: String = o.map(_.toString).getOrElse("left")
a: String = 5
I don't particularly like Either and as a result I'm not terribly familiar with it, but I believe you're looking for projections: either.left.getOrElse or either.right.getOrElse.
Note that projections can be used in for-comprehensions as well. This is an example straight from the documentation:
def interactWithDB(x: Query): Either[Exception, Result] =
try {
Right(getResultFromDatabase(x))
} catch {
case ex => Left(ex)
}
// this will only be executed if interactWithDB returns a Right
val report =
for (r <- interactWithDB(someQuery).right) yield generateReport(r)
if (report.isRight)
send(report)
else
log("report not generated, reason was " + report.left.get)
Given type A on both sides, that is, Either[A, A], we can use Either.merge
...to extract values from Either instances regardless of whether they are
Left or Right.
Note if left and right types differ then result is least upper bound of the two types which may become in worst case Any:
val e: Either[Int, String] = Right("hello")
e.merge // hello: Any
In Scala 2.12 there is a getOrElse method for getting the "right" value but you cannot use it for the "left" value directly. However, you can do it like this: e.swap.getOrElse(42).

How does Scala's groupBy identity work?

I was browsing around and found a question about grouping a String by it's characters, such as this:
The input:
"aaabbbccccdd"
Would produce the following output:
"aaa"
"bbb"
"cccc"
"ddd"
and I found this suggestion:
val str = "aaabbbccccdd"[
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
And this identity fellow got me curious. I found out it is defined in PreDef like this:
identity[A](x: A): A
So basically it returns whatever it is given, right? but how does that apply in the call to groupBy?
I'm sorry if this is a basic question, is just that functional programming is still tangling my brains a little. Please let me know if there's any information I can give to make this question clearer
This is your expression:
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
Let's go item by function by function. The first one is groupBy, which will partition your String using the list of keys passed by the discriminator function, which in your case is identity. The discriminator function will be applied to each character in the screen and all characters that return the same result will be grouped together. If we want to separate the letter a from the rest we could use x => x == 'a' as our discriminator function. That would group your string chars into the return of this function (true or false) in map:
Map(false -> bbbccccdd, true -> aaa)
By using identity, which is a "nice" way to say x => x, we get a map where each character gets separated in map, in your case:
Map(c -> cccc, a -> aaa, d -> dd, b -> bbb)
Then we convert the map to a list of tuples (char,String) with toList.
Order it by char with sortBy and just keep the String with the map getting your final result.
To understand this just call scala repl with -Xprint:typer option:
val res2: immutable.Map[Char,String] = augmentString(str).groupBy[Char]({
((x: Char) => identity[Char](x))
});
Scalac converts a simple String into StringOps with is a subclass of TraversableLike which has a groupBy method:
def groupBy[K](f: A => K): immutable.Map[K, Repr] = {
val m = mutable.Map.empty[K, Builder[A, Repr]]
for (elem <- this) {
val key = f(elem)
val bldr = m.getOrElseUpdate(key, newBuilder)
bldr += elem
}
val b = immutable.Map.newBuilder[K, Repr]
for ((k, v) <- m)
b += ((k, v.result))
b.result
}
So groupBy contains a map into which inserts chars return by identity function.
First, let's see what happens when you iterate over a String:
scala> "asdf".toList
res1: List[Char] = List(a, s, d, f)
Next, consider that sometimes we want to group elements on the basis of some specific attribute of an object.
For instance, we might group a list of strings by length as in...
List("aa", "bbb", "bb", "bbb").groupBy(_.length)
What if you just wanted to group each item by the item itself. You could pass in the identity function like this:
List("aa", "bbb", "bb", "bbb").groupBy(identity)
You could do something silly like this, but it would be silly:
List("aa", "bbb", "bb", "bbb").groupBy(_.toString)
Take a look at
str.groupBy(identity)
which returns
scala.collection.immutable.Map[Char,String] = Map(b -> bbb, d -> dd, a -> aaa, c -> cccc)
so the key by which the elements are grouped by is the character.
Whenever you try to use methods such as groupBy on the String. It's important to note that it is implicitly converted to StringOps and not List[Char].
StringOps
The signature of groupBy is given by-
def groupBy[K](f: (Char) ⇒ K): Map[K, String]
Hence, the result is in the form -
Map[Char,String]
List[Char]
The signature of groupBy is given by-
def groupBy[K](f: (Char) ⇒ K): Map[K, List[Char]]
If it had been implicitly converted to List[Char] the result would be of the form -
Map[Char,List[Char]]
Now this should implicitly answer your curious question, as how scala figured out to groupBy on Char (see the signature) and yet give you Map[Char, String].
Basically list.groupBy(identity) is just a fancy way of saying list.groupBy(x => x), which in my opinion is clearer. It groups a list containing duplicate items by those items.

Why is Seq.newBuilder returning a ListBuffer?

Looking at
val sb = Seq.newBuilder[Int]
println(sb.getClass.getName)
sb += 1
sb += 2
val s = sb.result()
println(s.getClass.getName)
the output is
scala.collection.mutable.ListBuffer
scala.collection.immutable.$colon$colon
using Scala 2.10.1.
I would expect Seq.newBuilder to return a VectorBuilder for example. This is returned by CanBuildFrom, if the result is explicitly typed to a Seq:
def build[T, C <: Iterable[T]](x: T, y: T)
(implicit cbf: CanBuildFrom[Nothing, T, C]): C = {
val b = cbf()
println(b.getClass.getName)
b += x
b += y
b.result()
}
val s: Seq[Int] = build(1, 2)
println(s.getClass.getName) // scala.collection.immutable.Vector
in this case the builder is a VectorBuilder, and the result's class is a Vector.
So I explicitly wanted to build a Seq, but the result is a List which needs more RAM, according to Scala collection memory footprint characteristics.
So why does Seq.newBuilder return a ListBuffer which gives a List in the end?
The Scala Collections API is very complex and its hierarchy is rich in depth. Each level represents some sort of new abstraction. The Seq trait split up into two different subtraits, which give different guarantees for performance (ref.):
An IndexedSeq provides fast random-access of elements and a fast length operation. One representative of this IndexedSeq is the Vector.
A LinearSeq provides fast access only to the first element via head, but also has a fast tail operation. One representative of this LinearSeq is the List.
As the current default implementation of a Seq is a List, Seq.newBuilder will return a ListBuffer. However, if you want to use a Vector you can either use Vector.newBuilder[T] or IndexedSeq.newBuilder[T]:
scala> scala.collection.immutable.IndexedSeq.newBuilder[Int]
res0: scala.collection.mutable.Builder[Int,scala.collection.immutable.IndexedSeq[Int]] = scala.collection.immutable.VectorBuilder#1fb10a9f
scala> scala.collection.immutable.Vector.newBuilder[Int]
res1: scala.collection.mutable.Builder[Int,scala.collection.immutable.Vector[Int]] = scala.collection.immutable.VectorBuilder#3efe9969
The default Seq implementation is List:
Seq(1, 2, 3) // -> List(1, 2, 3)
...thus ListBuffer is the correct builder. If you want Vector, use Vector.newBuilder or IndexedSeq.newBuilder.
OK, but you're not going to believe it. Turning on -Yinfer-debug for your CanBuildFrom counter-example,
[search] $line14.$read.$iw.$iw.build[scala.this.Int, Seq[scala.this.Int]](1, 2) with pt=generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]] in module class $iw, eligible:
fallbackStringCanBuildFrom: [T]=> generic.this.CanBuildFrom[String,T,immutable.this.IndexedSeq[T]]
[solve types] solving for T in ?T
inferExprInstance {
tree scala.this.Predef.fallbackStringCanBuildFrom[T]
tree.tpe generic.this.CanBuildFrom[String,T,immutable.this.IndexedSeq[T]]
tparams type T
pt generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
targs scala.this.Int
tvars =?scala.this.Int
}
[search] considering no tparams (pt contains no tvars) trying generic.this.CanBuildFrom[String,scala.this.Int,immutable.this.IndexedSeq[scala.this.Int]] against pt=generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
[success] found SearchResult(scala.this.Predef.fallbackStringCanBuildFrom[scala.this.Int], ) for pt generic.this.CanBuildFrom[scala.this.Nothing,scala.this.Int,Seq[scala.this.Int]]
[infer implicit] inferred SearchResult(scala.this.Predef.fallbackStringCanBuildFrom[scala.this.Int], )
and indeed,
implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =
new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {
def apply(from: String) = immutable.IndexedSeq.newBuilder[T]
def apply() = immutable.IndexedSeq.newBuilder[T]
}
What do you mean, your Iterable is not a String?
trait CanBuildFrom[-From, -Elem, +To]
Such is the evil of inferring either Nothing or Any.
Edit: Sorry, I misspoke, I see that you told it Nothing explicitly.
Update:
Since CBF is contravariant in From, a CBF from String serves as a CBF from Nothing.
scala> typeOf[CanBuildFrom[Nothing,Int,Seq[Int]]] <:< typeOf[CanBuildFrom[String,Int,Seq[Int]]]
res0: Boolean = false
scala> typeOf[CanBuildFrom[String,Int,Seq[Int]]] <:< typeOf[CanBuildFrom[Nothing,Int,Seq[Int]]]
res1: Boolean = true
For instance, if you need to build from an immutable.Map, you'd want a CBF from collection.Map to work.
As someone else commented, it's just weird for Nothing. But you get what you asked for. That is, you underspecified, which means you don't mind much what you get back, Vector or whatever.
I agree that this is weird. Why don't you just use Vector.newBuilder, if that's what you're looking for?
scala> val sb = Vector.newBuilder[Int]
sb: scala.collection.mutable.Builder[Int,scala.collection.immutable.Vector[Int]] = scala.collection.immutable.VectorBuilder#1fb7482a
scala> println(sb.getClass.getName)
scala.collection.immutable.VectorBuilder
scala> sb += 1
res1: sb.type = scala.collection.immutable.VectorBuilder#1fb7482a
scala> sb += 2
res2: sb.type = scala.collection.immutable.VectorBuilder#1fb7482a
scala> val s = sb.result()
s: scala.collection.immutable.Vector[Int] = Vector(1, 2)
scala> println(s.getClass.getName)
scala.collection.immutable.Vector