Trying to append to Iterable[String] - scala

I'm trying to add another string to Iterable[String] for easy concatenation, but the result is not what I expect.
scala> val s: Iterable[String] = "one string" :: "two string" :: Nil
s: Iterable[String] = List(one string, two string)
scala> s.mkString(";\n")
res3: String =
one string;
two string
scala> (s ++ "three").mkString(";\n")
res5: String =
one string;
two string;
t;
h;
r;
e;
e
How should I should I rewrite this snippet to have 3 string in my iterable?
Edit: I should add, that order of items should be preserved

++ is for collection aggregation. There is no method +, :+ or add in Iterable, but you can use method ++ like this:
scala> (s ++ Seq("three")).mkString(";\n")
res3: String =
one string;
two string;
three

The ++ function is waiting for a Traversable argument. If you use just "three", it will convert the String "three" to a list of characters and append every character to s. That's why you get this result.
Instead, you can wrap "three" in an Iterable and the concatenation should work correctly :
scala> (s ++ Iterable[String]("three")).mkString(";\n")
res6: String =
one string;
two string;
three

I like to use toBuffer and then +=
scala> val l : Iterable[Int] = List(1,2,3)
l: Iterable[Int] = List(1, 2, 3)
scala> val e : Iterable[Int] = l.toBuffer += 4
e: Iterable[Int] = ArrayBuffer(1, 2, 3, 4)
or in your example:
scala> (s.toBuffer += "three").mkString("\n")
I have no idea why this operation isn't supported in the standard library. You can also use toArray but if you add more than one element this will be less performant - I would assume - as the buffer should return itself if it another element is added.

Related

scala method call trick List(1, 2, 3).foldLeft(0) _+_

I came from What is the formal difference in Scala between braces and parentheses, and when should they be used?
, so still I am not clear understand the scala method call syntax trick. I think the lcn's answer in the link is clear but what does these mean:
val r = List(1, 2, 3).foldLeft(0) _+_ //r: String => String = $Lambda$1642/1200068083#562c1af9
val l = r{"hello"} //l: String = $Lambda$1643/1458648440#23ae6386hello
why r is a function? and call it return another function l and can not call l?
are there some official doc for method call in () and {}?
This has to do with operator precedence:
val r = List(1, 2, 3).foldLeft(0) _+_
Is equivalent to:
val r = (List(1, 2, 3).foldLeft(0) _) + _
Which means - we take the partially applied foldLeft function, List(1, 2, 3).foldLeft(0) _, which has the type ((Int, Int) => Int) => Int), and we call + _ on it.
Now - Scala compiler tries to figure out what the + operator should mean for a Function, and since Function does not define such an operator, it does the best it can to find a suitable implicit conversion, and finds that indeed the Function can be converted to a String using its toString method, so that the + _ means "a new anonymous function that appends any input String passed to the String representation of the List(1, 2, 3).foldLeft(0) _ function".
So we end up with a String => String function, that appends the input to the toString result of the function List(1, 2, 3).foldLeft(0) _, which is "<function1>":
scala> val r = List(1, 2, 3).foldLeft(0) _ + _
r: String => String = <function1>
scala> r("a")
res5: String = <function1>a
scala> r(" bbbb")
res6: String = <function1> bbbb

How to pad a Scala collection for minimum size?

How to make sure a Seq is of certain minimum length, in Scala?
The below code does what I want (adds empty strings until arr has three entries), but it feels clumsy.
scala> val arr = Seq("a")
arr: Seq[String] = List(a)
scala> arr ++ Seq.fill(3-arr.size)("")
res2: Seq[String] = List(a, "", "")
A way to fulfill this would be a merger of two sequences: take from first, but if it runs out, continue from second. What was such method called...?
I find this slightly better:
scala> (arr ++ Seq.fill(3)("")).take(3)
res4: Seq[String] = List(a, "", "")
And even better, thanks #thomas-böhm
scala> arr.toArray.padTo(3,"")
res5: Array[String] = Array(a, "", "")
arr.padTo(3,"")
It was too trivial.

Spark RDD tuple transformation

I'm trying to transform an RDD of tuple of Strings of this format :
(("abc","xyz","123","2016-02-26T18:31:56"),"15") TO
(("abc","xyz","123"),"2016-02-26T18:31:56","15")
Basically seperating out the timestamp string as a seperate tuple element. I tried following but it's still not clean and correct.
val result = rdd.map(r => (r._1.toString.split(",").toVector.dropRight(1).toString, r._1.toString.split(",").toList.last.toString, r._2))
However, it results in
(Vector(("abc", "xyz", "123"),"2016-02-26T18:31:56"),"15")
The expected output I'm looking for is
(("abc", "xyz", "123"),"2016-02-26T18:31:56","15")
This way I can access the elements using r._1, r._2 (the timestamp string) and r._3 in a seperate map operation.
Any hints/pointers will be greatly appreciated.
Vector.toString will include the String 'Vector' in its result. Instead, use Vector.mkString(",").
Example:
scala> val xs = Vector(1,2,3)
xs: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
scala> xs.toString
res25: String = Vector(1, 2, 3)
scala> xs.mkString
res26: String = 123
scala> xs.mkString(",")
res27: String = 1,2,3
However, if you want to be able to access (abc,xyz,123) as a Tuple and not as a string, you could also do the following:
val res = rdd.map{
case ((a:String,b:String,c:String,ts:String),d:String) => ((a,b,c),ts,d)
}

Scala Set with a Tuple of 3 Elements

How can I put in a tuple containing 3 elements to a Set?
Say, I have a Set of type:
Set[(String, String, String)]
How can I simply add 3 String's to my Set definition?
The following has the compiler complaining?
set + ("a", "b", "c")
Why is the tuple treated differently? It is just like any other type, so why it fails in my case above?
It doesn't parse well:
scala> Set[(String,String,String)]() + (("a", "b", "c"))
res3: scala.collection.immutable.Set[(String, String, String)] = Set((a,b,c))
What you wrote is parsed as Set.+(String x, String y, String z)
i.e., a function + with 3 string arguments, where what you wanted was a function + with a single 3-tuple as argument.
Note the signature of + for HashSet as an example:
def +(elem1: A, elem2: A, elems: A*): HashSet[A]
(from http://www.scala-lang.org/api/2.11.7/#scala.collection.immutable.HashSet)
This syntax implies that to add a tuple to a set of tuples would require double parentheses, one to accomodate the syntax of + and the other for the tuple. For example:
scala> import scala.collection.immutable.HashSet
import scala.collection.immutable.HashSet
scala> val set: Set[(String, String, String)] = new HashSet[(String, String, String)]()
set: Set[(String, String, String)] = Set()
scala> val newset = set + (("one", "two", "three"))
newset: scala.collection.immutable.Set[(String, String, String)] = Set((one,two,three))
This issue does not occur for sets of elements that are not bounded by parentheses since then there is no confusion with the syntax of +.

Simple question about tuple of scala

I'm new to scala, and what I'm learning is tuple.
I can define a tuple as following, and get the items:
val tuple = ("Mike", 40, "New York")
println("Name: " + tuple._1)
println("Age: " + tuple._2)
println("City: " + tuple._3)
My question is:
How to get the length of a tuple?
Is tuple mutable? Can I modify its items?
Is there any other useful operation we can do on a tuple?
Thanks in advance!
1] tuple.productArity
2] No.
3] Some interesting operations you can perform on tuples: (a short REPL session)
scala> val x = (3, "hello")
x: (Int, java.lang.String) = (3,hello)
scala> x.swap
res0: (java.lang.String, Int) = (hello,3)
scala> x.toString
res1: java.lang.String = (3,hello)
scala> val y = (3, "hello")
y: (Int, java.lang.String) = (3,hello)
scala> x == y
res2: Boolean = true
scala> x.productPrefix
res3: java.lang.String = Tuple2
scala> val xi = x.productIterator
xi: Iterator[Any] = non-empty iterator
scala> while(xi.hasNext) println(xi.next)
3
hello
See scaladocs of Tuple2, Tuple3 etc for more.
One thing that you can also do with a tuple is to extract the content using the match expression:
def tupleview( tup: Any ){
tup match {
case (a: String, b: String) =>
println("A pair of strings: "+a + " "+ b)
case (a: Int, b: Int, c: Int) =>
println("A triplet of ints: "+a + " "+ b + " " +c)
case _ => println("Unknown")
}
}
tupleview( ("Hello", "Freewind"))
tupleview( (1,2,3))
Gives:
A pair of strings: Hello Freewind
A triplet of ints: 1 2 3
Tuples are immutable, but, like all cases classes, they have a copy method that can be used to create a new Tuple with a few changed elements:
scala> (1, false, "two")
res0: (Int, Boolean, java.lang.String) = (1,false,two)
scala> res0.copy(_2 = true)
res1: (Int, Boolean, java.lang.String) = (1,true,two)
scala> res1.copy(_1 = 1f)
res2: (Float, Boolean, java.lang.String) = (1.0,true,two)
Concerning question 3:
A useful thing you can do with Tuples is to store parameter lists for functions:
def f(i:Int, s:String, c:Char) = s * i + c
List((3, "cha", '!'), (2, "bora", '.')).foreach(t => println((f _).tupled(t)))
//--> chachacha!
//--> borabora.
[Edit] As Randall remarks, you'd better use something like this in "real life":
def f(i:Int, s:String, c:Char) = s * i + c
val g = (f _).tupled
List((3, "cha", '!'), (2, "bora", '.')).foreach(t => println(g(t)))
In order to extract the values from tuples in the middle of a "collection transformation chain" you can write:
val words = List((3, "cha"),(2, "bora")).map{ case(i,s) => s * i }
Note the curly braces around the case, parentheses won't work.
Another nice trick ad question 3) (as 1 and 2 are already answered by others)
val tuple = ("Mike", 40, "New York")
tuple match {
case (name, age, city) =>{
println("Name: " + name)
println("Age: " + age)
println("City: " + city)
}
}
Edit: in fact it's rather a feature of pattern matching and case classes, a tuple is just a simple example of a case class...
You know the size of a tuple, it's part of it's type. For example if you define a function def f(tup: (Int, Int)), you know the length of tup is 2 because values of type (Int, Int) (aka Tuple2[Int, Int]) always have a length of 2.
No.
Not really. Tuples are useful for storing a fixed amount of items of possibly different types and passing them around, putting them into data structures etc. There's really not much you can do with them, other than creating tuples, and getting stuff out of tuples.
1 and 2 have already been answered.
A very useful thing that you can use tuples for is to return more than one value from a method or function. Simple example:
// Get the min and max of two integers
def minmax(a: Int, b: Int): (Int, Int) = if (a < b) (a, b) else (b, a)
// Call it and assign the result to two variables like this:
val (x, y) = minmax(10, 3) // x = 3, y = 10
Using shapeless, you easily get a lot of useful methods, that are usually available only on collections:
import shapeless.syntax.std.tuple._
val t = ("a", 2, true, 0.0)
val first = t(0)
val second = t(1)
// etc
val head = t.head
val tail = t.tail
val init = t.init
val last = t.last
val v = (2.0, 3L)
val concat = t ++ v
val append = t :+ 2L
val prepend = 1.0 +: t
val take2 = t take 2
val drop3 = t drop 3
val reverse = t.reverse
val zip = t zip (2.0, 2, "a", false)
val (unzip, other) = zip.unzip
val list = t.toList
val array = t.toArray
val set = t.to[Set]
Everything is typed as one would expect (that is first has type String, concat has type (String, Int, Boolean, Double, Double, Long), etc.)
The last method above (.to[Collection]) should be available in the next release (as of 2014/07/19).
You can also "update" a tuple
val a = t.updatedAt(1, 3) // gives ("a", 3, true, 0.0)
but that will return a new tuple instead of mutating the original one.