Scala makeString + pre + sep + post with foldLeft - scala

so I would like to create a string like "[a-to-b]"
def my func
def makeString(xs: List[String], pre : String, sep: String, post: String) : String =xs match{
case Nil => ""
case head::tail => xs.foldLeft(pre)((r,e) => r + sep + e) + post }
scala > makeString(List("a","to","b"), "[","-","]")
but it turned outString = [a-to-b-]
How can I fix it? Thanks

You've already extracted head and tail, you might as well use them for your foldLeft (instead of pre and xs) and put pre and post outside it.
def makeString(xs: List[String], pre : String, sep: String, post: String): String =
xs match {
case Nil => ""
case head::tail => pre + tail.foldLeft(head)((r,e) => r + sep + e) + post
}
Example Scastie

Related

Creating white space in a List in Scala

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, "")
}

Scala - standard recursive pattern match on list

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)
}

Convert Map to Json String format

I´m trying to convert a Map[String, Any] which Any contains as well sometimes a Map[String, Any] and so on, into Json String format.
I´ve found this external library http://json4s.org/ but amaze me that Scala core does not contain a native library to achieve this.
Any idea?
Regards.
Scala has not built-in feature, but it has amazing sintax... Here you have it, in 8 idiomatic lines:
def toJson(query: Any): String = query match {
case m: Map[String, Any] => s"{${m.map(toJson(_)).mkString(",")}}"
case t: (String, Any) => s""""${t._1}":${toJson(t._2)}"""
case ss: Seq[Any] => s"""[${ss.map(toJson(_)).mkString(",")}]"""
case s: String => s""""$s""""
case null => "null"
case _ => query.toString
}
Well JSON is an interchange format (albeit a popular one at present), but then so is XML etc etc. The core library arguably shouldn't concern itself with dealing with a long list of data formats - at least this is what I understand is the reason around limiting such support in Scala core, as in other languages.
There are quite a few libraries that will help you achieve this.
I currently use Argonaut for all things JSON in Scala projects, unless I am using Play, in which case it also provides pretty good JSON support. Have a look at Argonaut, you can achieve what you want to quite easily with it.
As far as I understood i thought that you are using your custom implementation for Json which is: Map[String, Any]
So here is custom implementation of function that will return String of your map
def show(json: Map[String, Any]) : String = {
def parse(elem: (String, Any)): String = elem match {
case (a: String, b: Map[String, _]) => "\"" + a + "\"" + ":" + show(b) + ""
case (a: String, b: Boolean) => "\"" + a + "\"" + ":" + b.toString
case (a: String, b: Int) => "\"" + a + "\"" + ":" + b.toString
case (a: String, b: Double) => "\"" + a + "\"" + ":" + b.toString
case (a: String, b: String) => "\"" + a + "\"" + ":\"" + b + "\""
}
val assocs = json.map {
case(key, value) => parse((key,value))
}
"{\n" + assocs.mkString(", \n")+ "}"
}
for such Map:
val mapJson = Map("root" ->
Map("field1" -> 1,
"field2" -> Map("field1" -> true,
"field2" -> 2.03),
"field3" -> "Test"))
it will print:
String = {
"root":{
"field1":1,
"field2":{
"field1":true,
"field2":2.03},
"field3":"Test"}}

save all parse results into one map in scala

Suppose I've got following txt file:
--quest_29540602496284069
Operator Name : Kevin
Account Id: 1444
Text: This is Kevin and this my text.
Age: 16
--quest_=29540602496284069--
I want to transform it to simple scala map:
(pseudo-code)
{
quest_id: 29540602496284069
operation_name = Kevin
account_id: 1444
text: This is Kevin and this my text.
operator_age: 16
}
So, i started to created case content class in order to store it in target object for future use:
case class MapContent(map: Map[String, String])
Then, i have created scala class with extending RegexpParsers:
class OperatorParser extends RegexParsers {
def parseFullRequest(input: String): MapContent = parseAll(parseRequest, input) match {
case Success(result, _) => result
case NoSuccess(msg, _) => throw new SomeParserException(msg)
}
// main entry
def parseRequest: Parser[MapContent] = parseQuestBody ~ parseAnotherBody
def parseQuestBody: Parser[MapContent] = parseQuestId
def parseQuestId: Parser[MapContent] = "--quest_" ~> """.+\n?""".r ^^ { case res =>
MapContent(Map("quest_id" -> res.toString))
}
def parseAnotherBody: Parser[MapContent] = """.+""".r ^^ { case res =>
MapContent(Map("another_body" -> res.toString))
}
}
When i'm doing
parseQuestBody ~ parseAnotherBody
it causes an error that Operator[MapContent, MapContent] isn't an Operator[MapContent]
I need a solution how to store exactly in MapContent during the whole parse process. Is there a possible way to do that? For now i can only store the quest_id number and not able to continue next.
You can use ^^ like in other parsers:
def parseRequest: Parser[MapContent] = parseQuestBody ~ parseAnotherBody ^^ {
case res => MapContent(res._1.map ++ res._2.map)
}
or
def parseRequest: Parser[MapContent] = parseQuestBody ~ parseAnotherBody ^^ {
case a ~ b => MapContent(a.map ++ b.map)
}
It transforms "tuple" of MapContents into single MapContent
Edit:
what if i will have a lot of text values, so in scala it will be
looking like a.map ++ b.map ++ c.map ++ d... + f.. + ... + x1 ? is
there more common way?
Folding it is one of possibilities:
def parseRequest: Parser[MapContent] = parseQuestId ~ rep(parseAnotherBody) ~ parseQuestId ^^ {
case value1 ~ list1 ~ value2=> {
val merged = List(value1, value2) ++ list1
merged.foldLeft(MapContent(Map.empty[String, String]))((a, b) => MapContent(a.map ++ b.map))
}
}
It returns map with only 2 values because you can't store in map 2 values with same another_body key

Why do I get "pattern type is incompatible with expected type"?

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!"