How to combine raw with string interpolation in Scala? - scala

Just started Scala and have a question.
val num = 10
val str = "Learning\t${num}Scala"
Now I am trying to print str without escaping \t but with num interpolation. Is this possible? Tried couple of variations below but they didn't work
scala>s"${str}"
scala>s"""${str}"""
scala>raw"""${str}"""
The question is how do I print Learning\t10Scala

Here is something that can be done, with same amount of code.
Write a function called times and make it insert some string in the middle of some other string
scala> def times(n: Int)(str: String): String = List.fill(n)(str).mkString("")
times: (n: Int)String
scala> s"""hello${times(3)("\t")}world"""
res0: String = hello world

Related

replace multiple occurrence of duplicate string in Scala with empty

I have a string as
something,'' something,nothing_something,op nothing_something,'' cat,cat
I want to achieve my output as
'' something,op nothing_something,cat
Is there any way to achieve it?
If I understand your requirement correctly, here's one approach with the following steps:
Split the input string by "," and create a list of indexed-CSVs and convert it to a Map
Generate 2-combinations of the indexed-CSVs
Check each of the indexed-CSV pairs and capture the index of any CSV which is contained within the other CSV
Since the CSVs corresponding to the captured indexes are contained within some other CSV, removing these indexes will result in remaining indexes we would like to keep
Use the remaining indexes to look up CSVs from the CSV Map and concatenate them back to a string
Here is sample code applying to a string with slightly more general comma-separated values:
val str = "cats,a cat,cat,there is a cat,my cat,cats,cat"
val csvIdxList = (Stream from 1).zip(str.split(",")).toList
val csvMap = csvIdxList.toMap
val csvPairs = csvIdxList.combinations(2).toList
val csvContainedIdx = csvPairs.collect{
case List(x, y) if x._2.contains(y._2) => y._1
case List(x, y) if y._2.contains(x._2) => x._1
}.
distinct
// csvContainedIdx: List[Int] = List(3, 6, 7, 2)
val csvToKeepIdx = (1 to csvIdxList.size) diff csvContainedIdx
// csvToKeepIdx: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 5)
val strDeduped = csvToKeepIdx.map( csvMap.getOrElse(_, "") ).mkString(",")
// strDeduped: String = cats,there is a cat,my cat
Applying the above to your sample string something,'' something,nothing_something,op nothing_something would yield the expected result:
strDeduped: String = '' something,op nothing_something
First create an Array of words separated by commas using split command on the given String, and do other operations using filter and mkString as below:
s.split(",").filter(_.contains(' ')).mkString(",")
In Scala REPL:
scala> val s = "something,'' something,nothing_something,op nothing_something"
s: String = something,'' something,nothing_something,op nothing_something
scala> s.split(",").filter(_.contains(' ')).mkString(",")
res27: String = '' something,op nothing_something
As per Leo C comment, I tested it as below with some other String:
scala> val s = "something,'' something anything anything anything anything,nothing_something,op op op nothing_something"
s: String = something,'' something anything anything anything anything,nothing_something,op op op nothing_something
scala> s.split(",").filter(_.contains(' ')).mkString(",")
res43: String = '' something anything anything anything anything,op op op nothing_something

Concatenate characters in Scala

Suppose we have a string "code". How would we concatenate any two characters? Say for example we need to concatenate last two characters,
str.init.last + str.last gives result as 201. How would we get de instead?
You can use string interpolation to make any combination of characters:
scala> val code = "code"
code: String = code
scala> s"${code(1)}${code(3)}"
res0: String = oe
"code".init.last.toString + "code".last.toString
val res7: String = de
(use toString first to convert char to String and then concatenate with +)

Split function difference between char and string arguments

I try the following code in scala REPL:
"ASD-ASD.KZ".split('.')
res7: Array[String] = Array(ASD-ASD, KZ)
"ASD-ASD.KZ".split(".")
res8: Array[String] = Array()
Why this function calls have a different results?
There's a big difference in the function use.
The split function is overloaded, and this is the implementation from the source code of Scala:
/** For every line in this string:
Strip a leading prefix consisting of blanks or control characters
followed by | from the line.
*/
def stripMargin: String = stripMargin('|')
private def escape(ch: Char): String = "\\Q" + ch + "\\E"
#throws(classOf[java.util.regex.PatternSyntaxException])
def split(separator: Char): Array[String] = toString.split(escape(separator))
#throws(classOf[java.util.regex.PatternSyntaxException])
def split(separators: Array[Char]): Array[String] = {
val re = separators.foldLeft("[")(_+escape(_)) + "]"
toString.split(re)
}
So when you're calling split() with a char, you ask to split by that specific char:
scala> "ASD-ASD.KZ".split('.')
res0: Array[String] = Array(ASD-ASD, KZ)
And when you're calling split() with a string, it means that you want to have a regex. So for you to get the exact result using the double quotes, you need to do:
scala> "ASD-ASD.KZ".split("\\.")
res2: Array[String] = Array(ASD-ASD, KZ)
Where:
First \ escapes the following character
Second \ escapes character for the dot which is a regex expression, and we want to use it as a character
. - the character to split the string by

Scala finding more elegant way

I am new to Scala and functional programming.
I was solving problem where you have to read number, and then that number of integers. After that you should calculate sum of all digits in all the integers.
Here is my code
def sumDigits(line: String) =
line.foldLeft(0)(_ + _.toInt - '0'.toInt)
def main(args: Array[String]) {
val numberOfLines = Console.readInt
val lines = for (i <- 1 to numberOfLines) yield Console.readLine
println(lines.foldLeft(0)( _ + sumDigits(_)))
}
Is there more elegant or efficient way?
sumDigits() can be implemented easier with sum:
def sumDigits(line: String) = line.map(_.asDigit).sum
Second foldLeft() can also be replaced with sum:
lines.map(sumDigits).sum
Which brings us to the final version (notice there is no main, instead with extend App):
object Main extends App {
def sumDigits(line: String) = line.map(_.asDigit).sum
val lines = for (_ <- 1 to Console.readInt) yield Console.readLine
println(lines.map(sumDigits).sum)
}
Or if you really want to squeeze as much as possible in one line, inline sumDigits (not recommended):
lines.map(_.map(_.asDigit).sum).sum
I like compact code, so I might (if I was really going for brevity)
object Reads extends App {
import Console._
println( Seq.fill(readInt){readLine.map(_ - '0').sum}.sum )
}
which sets the number of lines inline and does the processing as you go. No error checking, though. You could throw in a .filter(_.isDigit) right after the readLine to at least discard non-digits. You might also def p[A](a: A) = { println(a); a } and wrap the reads in p so you can see what had been typed (by default on some platforms at least there's no echo to screen).
One-liner Answer:
Iterator.continually(Console.readLine).take(Console.readInt).toList.flatten.map(_.asDigit).sum
To start with, you have to do some kind of parsing on line to break apart the existing decimal integers sub-strings:
val numbers = "5 1 4 9 16 25"
val ints = numbers.split("\\s+").toList.map(_.toInt)
Then you want to pull off the first one as the count and keep the rest to decode and sum:
val count :: numbers = ints
Then use the built-in sum method:
val sum = numbers.sum
Altogether in the REPL:
scala> val numbers = "5 1 4 9 16 25"
numbers: String = 5 1 4 9 16 25
scala> val ints = numbers.split("\\s+").toList.map(_.toInt)
ints: List[Int] = List(5, 1, 4, 9, 16, 25)
scala> val count :: numbers = ints
count: Int = 5
numbers: List[Int] = List(1, 4, 9, 16, 25)
scala> val sum = numbers.sum
sum: Int = 55
If you want to do something with the leading number count, you could verify that it's correct:
scala> assert(count == numbers.length)
Which produces no output, since the assertion passes.

how would I map a list of strings with a known format to a list of tuples?

I have an array of strings. Each string has 2 parts and is separated by white space. Looks like:
x <white space> y
I want to turn it into an array of Tuples where each tuple has (x, y)
How can I write this in scala? I know it will need something similar to:
val results = listOfStrings.collect { str => (str.left, str.right) }
not sure how i can break up each str to the left and right sides needed...
You could take advantage of the fact that in Scala, Regular expressions are also "extractors".
scala> var PairWithSpaces = "(\\w+)\\s+(\\w+)".r
PairWithSpaces: scala.util.matching.Regex = (.+)\s+(.+)
scala> val PairWithSpaces(l, r) = "1 17"
l: String = 1
r: String = 17
Now you can build your extractor into a natural looking "map":
scala> Array("a b", "1 3", "Z x").map{case PairWithSpaces(x,y) => (x, y) }
res10: Array[(String, String)] = Array((a,b), (1,3), (Z,x))
Perhaps overkill for you, but can really help readability if your regex gets fancy. I also like how this approach will fail fast if an illegal string is given.
Warning, not sure if the regex matches exactly what you need...
You could (assuming that you want to drop without complaint any string that doesn't fit the pattern):
val results = listOfStrings.map(_.split("\\s+")).collect { case Array(l,r) => (l,r) }