I am trying to convert a List of string to the form "rBrrBB", or "r r rb", or " rrB". The string must have length 6. If the this list is not full, then the list should be prefixed with an appropriate number of spaces
So far my code as below
def showColumn(xs: List[String]): String = xs match
{case List() => ""
case x::xs1 => x.format(" ") + showColumn(xs1)}
when I call this from
println (showColumn(List("","","b","b","r","b")))
it returns only "bbrb". It suppose to return " bbrb"
Any help would appreciate.
Try this:
def showColumn(xs: List[String]): String = xs.map(x => if(x == "") " " else x).mkString
or, alternatively:
def showColumn(xs: List[String]): String = xs.map(x => if(x.isEmpty) " " else x).mkString
Both work by changing empty strings in the list to spaces, then merging each string in the list into a single string.
If you absolutely must make this a recursive function, then a solution which is not tail-recursive would look like this:
def showColumn(xs: List[String]): String = xs match {
case Nil => ""
case x :: xs1 => (if(x.isEmpty) " " else x) + showColumn(xs1)
}
Finally, the tail-recursive version is a little more complex, as it employs a helper function:
import scala.annotation.tailrec
def showColumn(xs: List[String]): String = {
// Tail recursive helper function.
#tailrec
def nextStr(rem: List[String], acc: String): String = rem match {
case Nil => acc
case x :: xs1 => nextStr(xs1, acc + (if(x.isEmpty) " " else x))
}
// Start things off.
nextStr(xs, "")
}
Related
Given:
def readLines(x: String): List[String] = Source.fromFile(x).getLines.toList
def toKVMap(fName : String): Map[String,String] =
readLines(fName).map(x => x.split(',')).map { case Array(x, y) => (x, y) }.toMap
I want to be able to take a string and a list of files of replacements and replace bracketed items. So if I have:
replLines("Hello",["cat"]) and cat contains ello,i!, I want to get back Hi!
I tried:
def replLines(inpQ : String, y : List[String]): String = y match {
case Nil => inpQ
case x::xs => replLines(toKVMap(x).fold(inpQ) {
case ((str: String), ((k: String), (v: String))) =>
str.replace("[" + k + "]", v).toString
}, xs)
}
I think the syntax is close, but not quite there. What have I done wrong?
What you're looking for is most likely this (note the foldLeft[String] instead of fold:
def replLines(inpQ: String, y: List[String]): String = y match {
case Nil => inpQ
case x :: xs => replLines(toKVMap(x).foldLeft[String](inpQ) {
case ((str: String), ((k: String), (v: String))) =>
str.replace("[" + k + "]", v)
}, xs)
}
fold generalizes the fold initial argument too much, and considers it a Serializable, not a String. foldLeft (and foldRight, if you prefer to start your replacements from the end) allows you to explicitly specify the type you fold on
EDIT: In fact, you don't even need a recursive pattern matching at all, as you can map your replacements directly to the list:
def replLines2(inpQ: String, y: List[String]): String =
y.flatMap(toKVMap).foldLeft[String](inpQ) {
case (str, (k, v)) => str.replace(s"[$k]", v)
}
I have a list and two strings :
val features = List("one","two","three")
val strOne = "one_five"
val strTwo = "seven_five"
I'd like to match each string to items of the list.
If beginning of string matches one of list items then print matched list item and string itself.
If not, nothing to print.
I have method that I think make what I need but I cannot compile it :
def getElement(any: String): String = any match {
case s :: rest if features.contains(s) => s + "= " + any
case _ => // Nothing
}
I wanted the following :
scala> getElement(strOne)
"one_five= one"
scala> getElement(strTwo)
You can't just return nothing. You promised that your method would return a String, so you must return one. You can either return an Option[String] (preferred) or return Unit and do the printing yourself. Further, the built in method TraversableLike#find will do part of the job.
def findFeature(str: String): Option[String] = features.find(_ startsWith str) map { value => s"$str=$value" }
In order to get the printing behavior:
findFeature(str) foreach println
// or redefine findFeature similarly
Further, you seem to misunderstand pattern matching: You don't want to match on the string; you want to match the list's elements against the string. Here's a version that uses pattern matching:
def getElement(feature: String): Option[String] = {
#tailrec def getElem0(feature: String, strs: List[String]): Option[String] = strs match {
case s :: _ if s startsWith feature => Some(s"$feature=$s") // Matching case
case _ :: rest => getElem0(feature, rest) // Not matched, but more to search
case Nil => None // Empty list; failure
}
getElem0(feature, features)
}
Your solution can't compile because :: is a List method, and s is a String. Moreover, getElement is declared to return a String therefore it should return a String for any input. So you can't just return "nothing" in the second case.
Here's an alternative implementation:
def printElement(any: String): Unit = features
.find(s => any.startsWith(s)) // find matching (returns Option[String])
.foreach(s => println(s + "= "+ any)) // print if found
printElement(strOne) // one= one_five
printElement(strTwo)
Simple one line Scala code
Find in list the item who's first part is present in the list
features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Put the above line inside the function.
def getElement(str: String): String = features.find(_ == str.split("_")(0)).map { elem => s"$str= $elem"}.getOrElse("")
Scala REPL
scala> val strOne = "one_five"
strOne: String = one_five
scala> val str = "one_five"
str: String = one_five
scala> features.find(_ == str.split("_")(0)).getOrElse("")
res2: String = one
scala> features.find(_ == str.split("_")(0)).map(elem => s"$str= $elem").getOrElse("")
res3: String = one_five= one
I'm currently learning Scala and I'm amazed. The language handles so much problems quite elegant. But, I got a problem when it comes to matching the last element of a list.
Let's have a look at this code:
def stringify(list: List[String]): String = list match {
case x :: xs => x + (if (xs.length != 0) ":" else "") + stringify(xs)
case Nil => ""
}
This is quite inelegant and I would like to write it more intuitive, something like this:
def stringify(list: List[String]): String = list match {
case x :: xs => x + ":" + stringify(xs)
case x :: Nil => x
}
How can I do that?
You need to switch the order. The xs symbol will eagerly match anything in that position. Trying to match Nil first will make that statement no longer unreachable. Also, you'll still need to match Nil by itself to account for empty lists.
def stringify(list: List[String]): String = list match {
case x :: Nil => x
case x :: xs => x + ":" + stringify(xs)
case Nil => ""
}
Though mkString already does what you're looking to make.
Here's an implementation using List#foldRight:
def stringify(list: List[String]): String =
list.foldRight(""){
(e, acc) => if (acc.isEmpty) e
else { e + ":" + acc }
}
When folding over this list, we need to check for when the accumulator is empty. Otherwise, we'll get an extra : at the end of the stringfied string result.
Tests
scala> stringify(List("1", "2" , "3") )
res6: String = 1:2:3
scala> stringify(List("1", "2" , "3", "500") )
res7: String = 1:2:3:500
I came across with an error on my Scala code that I cannot solve by myself (I am new at Scala).
I have the following code:
def myFunction(list: List[Any]): String = {
var strItems : String = "";
list.foreach(item => {
strItems += item match {
case x:JsonSerializable => x.toJson()
case y:String => ("\"" + y + "\"")
case _ => item.toString
}
if(item != list.last)
strItems += ",";
})
strItems;
}
The error I am getting is:
error: pattern type is incompatible with expected type;
found : String
required: Unit
case y:String => ("\"" + y + "\"")
Any idea why?
PS: is there a more performant way to code myFunction
In terms of the original question, the code doesn't compile because it requires parentheses around the match, ie. strItems += (item match { ... })
A more "functional" way of writing this could be something along the lines of:
def myFunction(list:List[Any]):String = {
val strings:List[String] = list.map{
case x:JsonSerializable => x.toJson()
case y:String => ("\"" + y + "\"")
case z => z.toString
}
strings.mkString(",")
}
You could probably use a view to make it lazy and more "performant", although I don't know off the top of my head if that would combine the two underlying loops (map & mkString) into a single traversal.
Here's a form of your code that compiles (w/o any definition for JsonSerializable) (in Scala 2.8) along with a more succinct formulation (that also happens to be point-free):
object Javier01 {
def
javFunc(list: List[Any]): String = {
val strItems = new StringBuilder()
list.foreach { item =>
strItems.append ( item match {
// case x: JsonSerializable => x.toJson()
case y: String => "\"" + y + "\""
case _ => item.toString
} )
if (item != list.last)
strItems.append(",")
}
strItems.toString
}
def
rrsFunc(anys: List[Any]): String =
anys map {
// case x: JsonSerializable => x.toJson()
case s: String => "\"" + s + "\""
case x => x.toString
} mkString ","
def
main(args: Array[String]): Unit = {
val stuff = List(true, 1, 123.456, "boo!")
printf(" stuff : %s%njavFunc(stuff): %s%nrrsFunc(stuff): %s%n%n",
stuff, javFunc(stuff), rrsFunc(stuff))
}
}
The output from running this is:
% scala Javier01
stuff : List(true, 1, 123.456, boo!)
javFunc(stuff): true,1,123.456,"boo!"
rrsFunc(stuff): true,1,123.456,"boo!"
Scala Newbie alert:
basically I'm trying to do something like this: where I pattern match and return a String.
scala> def processList(list: List[String], m: String): String={list foreach (x=> m match{
| case "test" => "we got test"
| case "test1"=> "we got test1"})}
:10: error: type mismatch;
found : Unit
required: String
def processList(list: List[String], m: String): String={list foreach (x=> m match{
I know I can set a var and return it after the for comp... but that doesn't seem to be the Scala way.
It is not completely clear to me what exactly it is that you are trying to do. Do you just want to test whether a certain element is present in the list? Or do you want to return a list of strings with some transformation? The latter, for example, can be written like so:
scala> def processList(l: List[String]): List[String] = l map {s => s match {
case "test" => "we got test"
case "test1" => "we got test1"
case _ => "we got something else"
}
}
scala> processList(List("test", "test1", "test2", "test3"))
res: List[String] = List(we got test, we got test1, we got something else, we got something else)
And for the former you could write something like:
scala> def exists(l: List[String], m: String): String = {
if (l exists (s => s == m))
m + " exists"
else
m + " does not exist"
}
exists: (l: List[String],m: String)String
scala> val l = List("test1", "test2", "test3")
l: List[java.lang.String] = List(test1, test2, test3)
scala> exists(l, "test1")
res0: String = test1 exists
scala> exists(l, "test2")
res1: String = test2 exists
scala> exists(l, "test8")
res2: String = test8 does not exist
In any case: the foreach method on a List loops over every element in a list, applying the given function to each element. It is mainly used for side-effecting, such as printing something to the console, or writing to a file. The function passed to the foreach method,must return the Unit type, which is like void in Java. You cannot return a single String from it, therefore.
You need to use map, not foreach. And then you can either return the list of strings (just as you've written, except the return type is List[String]) or you can stick them together using .mkString(" ") (that will put spaces between them).
def processList(list: List[String], m: String): String= {
list foreach (x=> m match {
case "test" => return "we got test"
case "test1"=> return "we got test1"
})
error("oops")
}
To return a single result on the fly - maybe by concatenating the single results, you may use (INIT /: COLLECTION) (_ OPERATION _) like this:
val li = List ("test", "test", "test1", "test")
("" /: li) ((x, y) => x + { y match {
case "test" => "we got test\n"
case "test1" => "we got test 1\n" } } )
res74: java.lang.String =
we got test
we got test
we got test 1
we got test