Yield String from List[Char] - scala

I have a l: List[Char] of characters which I want to concat and return as a String in one for loop.
I tried this
val x: String = for(i <- list) yield(i)
leading to
error: type mismatch;
found : List[Char]
required: String
So how can I change the result type of yield?
Thanks!

Try this:
val x: String = list.mkString
This syntax:
for (i <- list) yield i
is syntactic sugar for:
list.map(i => i)
and will thus return an unchanged copy of your original list.

You can use the following:
val x: String = (for(i <- list) yield(i))(collection.breakOut)
See this question for more information about breakOut.

You can use any of the three mkString overloads. Basically it converts a collection into a flat String by each element's toString method. Overloads add custom separators between each element.
It is a Iterable's method, so you can also use it in Map or Set.
See http://www.scala-lang.org/api/2.7.2/scala/Iterable.html for more details.

Related

Scala: type check on yield that may return an empty list

I have to following code in Scala, that's meant to return sentences.
val x: List[Word] = for (word <- words) yield {
if (word.isLegit()) sentenceStartingWith(word)
}
I'm getting an error because the type of x is not List[word] but Any (because it may not yield anything). Casting didn't help.
The simple fix that came to mind was
val x: List[Word] = for (word <- words) yield {
if (word.isLegit()) sentenceStartingWith(word)
else List[Word]()
}
But this returns a list with a lot of empty lists as members. How can I get the behavior I want, which is to return a List[word] with all the items if finds (or empty if it finds none)
I'm getting an error because the type of x is not List[word] but Any
The compiler is inferring what you're trying to do. What it sees is that you only return a value when your if statement is matched, thus it implicitly returns List[Any] (via List.canBuildFrom[Any]) for anything that doesn't match the predicate. Thus, the common supertype of both Seq[Any].
One possible way of doing this would be using a guard to filter out words first:
val x: List[Word] = for (word <- words if word.isLegit()) yield sentenceStartingWith(word)
This is equivalent to:
val x = words.withFilter(_.isLegit()).map(word => sentenceStartingWith(word))
Note methods in Scala are camelCase, and class names are PascalCase.
Try This
val x: List[word] = for (word <- words if (word.isLegit())) yield {word}

How do I append to a listbuffer which is a value of a mutable map in Scala?

val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap("key") = collection.mutable.ListBuffer("a","b")
mymap.get("key") += "c"
The last line to append to the list buffer is giving error. How the append can be done ?
When you run the code in the scala console:
→$scala
scala> val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap: scala.collection.mutable.Map[String,Seq[String]] = Map()
scala> mymap("key") = collection.mutable.ListBuffer("a","b")
scala> mymap.get("key")
res1: Option[Seq[String]] = Some(ListBuffer(a, b))
You'll see that mymap.get("key") is an optional type. You can't add a string to the optional type.
Additionally, since you typed mymap to Seq[String], Seq[String] does not have a += operator taking in a String.
The following works:
val mymap= collection.mutable.Map.empty[String,collection.mutable.ListBuffer[String]]
mymap("key") = collection.mutable.ListBuffer("a","b")
mymap.get("key").map(_ += "c")
Using the .map function will take advantage of the optional type and prevent noSuchElementException as Łukasz noted.
To deal with your problems one at a time:
Map.get returns an Option[T] and Option does not provide a += or + method.
Even if you use Map.apply (mymap("key")) the return type of apply will be V (in this case Seq) regardless of what the actual concrete type is (Vector, List, Set, etc.). Seq does not provide a += method, and its + method expects another Seq.
Given that, to get what you want you need to declare the type of the Map to be a mutable type:
import collection.mutable.ListBuffer
val mymap= collection.mutable.Map.empty[String,ListBuffer[String]]
mymap("key") = ListBuffer("a","b")
mymap("key") += "c"
will work as you expect it to.
If you really want to have immutable value, then something like this should also work:
val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap("key") = Vector("a","b")
val oldValue = mymap.get("key").getOrElse(Vector[String]())
mymap("key") = oldValue :+ "c"
I used Vector here, because adding elements to the end of List is unefficient by design.

Scala convert Option[T] to String

Does exist any native function in scala that does the equivalent this?
def strConvert[T](v: Option[T]): String = {
if (v.isDefined)
v.get.toString
else
""
}
For generic T, you can avoid the if with map -- v.map(_.toString).getOrElse("")
scala> Some(1).fold("")(_.toString)
res0: String = 1
scala> None.fold("")(_.toString)
res1: String = ""
Option is a monad. In FP, when working with monads, you define what you want to happen if the monad contains a state (i.e. a value other than None). Otherwise, you move on.
val ostring: Option[String] = functionThatGetsOptionString()
ostring.map { s =>
functionThatUsesString(s)
}
Within the map function, s will contain the raw string if the Option is Some(String) otherwise it won't execute the inner body if Option is None.

Scala Type Mismatch underlying type

I'm writing methods to convert Set[Tuple2[String, String]] to String and vice versa.
I'm saving the string value as v1,v2#v3,v4#v5,v6
In order to fill the Set I'm splitting the string by ',' and in order to extract the values I'm trying to split each value by '#' but i receive
type mismatch: found: x.type (with underlying type Array[String]
The code I tried using is
val x = overwriters.split("#")
for(tuple <- x) {
tuple.split(",")
}
The returned type of split is an array of String so it is not clear to me why i cannot split each member of the returned array
tuple.split(",") returns an array of two elements. You need to convert it to a tuple.
val overwriters ="v1,v2#v3,v4#v5,v6"
val x = overwriters.split("#").toSet
for(tuple <- x) yield {
val t = tuple.split(",")
(t(0),t(1))
}
overwrites.split("#").map(_.split(",")).map(x=> (x(0),x(1))).toSet
This will achieve the same in little more idiomatic way.

What does _ :: mean in Scala?

I am going through a book Lift in action and I encountered something I don't quite understand: _ ::
object permanent_link extends MappedString(this, 150){
override def validations =
valMinLen(3, "Link URL must be at least 5 characters") _ ::
super.validations
}
I can't find any hint so I would be grateful if anyone could help me out..
I don't know Lift, but this is a general question. First of all, the :: is a Scala cons operator:
scala> 1 :: 2 :: List(3, 4)
res0: List[Int] = List(1, 2, 3, 4)
This means that super.validations is some sort of a sequence and valMinLen(3, "Link URL must be at least 5 characters") _ is a single value in that list.
From the context it looks obvious that in overridden validations method they are calling super version and prepend some extra validation at the beginning.
This extra validation is created by a call to valMinLen(). However this extra call does not return an element matching the type of validations list - but a function. Instead of prepending the function value we are explicitly saying (by adding _ suffix`) that we want to prepend a function itself, not a return value of that function.
Code snippet is worth a thousand words:
scala> def f = 3
f: Int
scala> def g = 4
g: Int
scala> val listOfInts = List(f, g)
listOfInts: List[Int] = List(3, 4)
scala> val listOfFunctions = List(f _, g _)
listOfFunctions: List[() => Int] = List(<function0>, <function0>)
Compare the type of listOfInts and listOfFunctions. I believe the f _ syntax is called partially applied function in Scala world.
The underscore ignifies that valMinLen isn't to be called but be used as a function "pointer".
The :: operator concatenates lists.
It would in other words seem like the code builds a list validations that consist of a function "pointer" to valMinLen with the parameters given and the rest of the list is the value of super.validations, that is the super class' validations.
I'm sure someone will correct my terminology here :)
The code might be more readable with some proper indentation and introducing a val:
object permanent_link extends MappedString(this, 150) {
override def validations = minimumValidation :: super.validations
val minimumValidation = valMinLen(3,"Link URL must be at least 5 characters") _
}
So as noted before, the :: operator just prepends a new element to a list, the _ has nothing to do with it and is used to obtain a function object, like in
(1 :: 2 :: Nil) map (println _)
which makes a list [1, 2] and applies the function println to every element (the underscore can actually be omitted here). The object println _ constructs a function object from the println method with the _ representing the function's single parameter.