Why the result is not the same, f Interpolator in scala - scala

val bb =0
val cc ="%07d"
println(f"$bb$cc") //0%07d
println(f"$bb%07d") //0000000
I expect
println(f"$bb$cc") //0000000
println(f"$bb%07d") //0000000
Why isn't the result the same?
How can I make it the same?

By using f"string" you are declaring that you want to make a formatted string.
with f"$bb$cc" you are using the variables bb and cc, so it accesses the strings for them
with f"$bb%07d" you are telling it to transform bb into a number with 7 decimal places, and 0s if the number isn't large enough
further examples to help understanding:
val bb = 1
println(f"$bb%07d") // 0000001
println(f"$bb%05d") // 00001
val bb = 11
println(f"$bb%05d") //00011
to get the same string, try using s"string"
val bb = 0
println(s"$bb%07d") // 0%07d
to use a string as a formatter:
val cc = "%07d"
val bb = 0
println(cc.format(bb)) //0000000
//for more information http://docs.scala-lang.org/overviews/core/string-interpolation.html

I think that you already know that, but just to be clear:
$ is used for marking of variable references
% is used for formatting the references
Generally you use f interpolator like this: f"$<reference>%<format>"
When you write:
println(f"$bb$cc")
This is what happens:
Parser recognizes $bb with no formatting.
Parser recognizes $cc with no formatting.
Substitutes $bb with 0
Substitutes $bb with "%07d"
But when you write:
println(f"$bb%07d")
This is what happens:
Parser recognizes $bb with formatting 07d
Substitutes $bb with 0 and formats it according to "07d", that is: 7 digits and filling with 0 is number is shorter than 7 digits.
You might have thought of this method as being preprocessing like #define cc "%07d" in C but it's simply not.
I'm not currently aware of a way to store the formatting in a separate string. You might consider using a class-based formatter for doing so.

String interpolation syntax requires a string literal.
The point of the f-interpolator macro is to give compile-time safety.
scala> val x = 0.1
x: Double = 0.1
scala> f"$x"
res0: String = 0.1
scala> f"$x%5.5f"
res1: String = 0.10000
scala> f"$x%5d"
<console>:13: error: type mismatch;
found : Double
required: Int
f"$x%5d"
^
scala> val fmt = "%5d"
fmt: String = %5d
scala> fmt format x
java.util.IllegalFormatConversionException: d != java.lang.Double
at java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:4302)
at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2793)
at java.util.Formatter$FormatSpecifier.print(Formatter.java:2747)
at java.util.Formatter.format(Formatter.java:2520)
at java.util.Formatter.format(Formatter.java:2455)
at java.lang.String.format(String.java:2940)
at scala.collection.immutable.StringLike$class.format(StringLike.scala:318)
at scala.collection.immutable.StringOps.format(StringOps.scala:29)
... 32 elided
This isn't convenient, but you can decompose the string constants and roll it by hand:
scala> final val fmt = "%5d"
fmt: String("%5d") = %5d
scala> new StringContext("", fmt).f(x)
<console>:14: error: type mismatch;
found : Double
required: Int
new StringContext("", fmt).f(x)
^
or
scala> final val fmt = "%5.5f"
fmt: String("%5.5f") = %5.5f
scala> new StringContext("", fmt).f(x)
res8: String = 0.10000
scala> final val fmt = "%5.5"
fmt: String("%5.5") = %5.5
scala> new StringContext("", fmt + "f").f(x)
res9: String = 0.10000
scala> new StringContext("", fmt + "d").f(x)
<console>:14: error: precision not allowed
new StringContext("", fmt + "d").f(x)
^
scala> final val fmt = "%5"
fmt: String("%5") = %5
scala> new StringContext("", fmt + "d").f(x)
<console>:14: error: type mismatch;
found : Double
required: Int
new StringContext("", fmt + "d").f(x)
^
The error if you try it with non-constant String:
scala> val fmt = "%5d"
fmt: String = %5d
scala> new StringContext("", fmt).f(x)
<console>:14: error: exception during macro expansion:
java.lang.IllegalArgumentException: internal error: argument parts must be a list of string literals
at scala.tools.reflect.FormatInterpolator.scala$tools$reflect$FormatInterpolator$$copyPart$1(FormatInterpolator.scala:82)
at scala.tools.reflect.FormatInterpolator.interpolated(FormatInterpolator.scala:181)
at scala.tools.reflect.FormatInterpolator.interpolate(FormatInterpolator.scala:38)
at scala.tools.reflect.FastTrack$$anonfun$1$$anonfun$apply$5$$anonfun$applyOrElse$5.apply(FastTrack.scala:54)
at scala.tools.reflect.FastTrack$$anonfun$1$$anonfun$apply$5$$anonfun$applyOrElse$5.apply(FastTrack.scala:54)
at scala.tools.reflect.FastTrack$FastTrackEntry.apply(FastTrack.scala:41)
at scala.tools.reflect.FastTrack$FastTrackEntry.apply(FastTrack.scala:36)
at scala.tools.nsc.typechecker.Macros$class.macroExpandWithRuntime(Macros.scala:763)
new StringContext("", fmt).f(x)
^

Related

How do I extract each words from a text file in scala

I'm pretty much new to Scala. I have a text file that has only one line with file words separated by a semi-colon(;).
I want to extract each word, remove the white spaces, convert all to lowercase and call them based on the index of each word. Below is how I approached it:
newListUpper2.txt contains (Bed; chairs;spoon; CARPET;curtains )
val file = sc.textFile("myfile.txt")
val lower = file.map(x=>x.toLowerCase)
val result = lower.flatMap(x=>x.trim.split(";"))
result.collect.foreach(println)
Below is the copy of the REPL when I executed the code
scala> val file = sc.textFile("newListUpper2.txt")
file: org.apache.spark.rdd.RDD[String] = newListUpper2.txt MapPartitionsRDD[5] at textFile at
<console>:24
scala> val lower = file.map(x=>x.toLowerCase)
lower: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[6] at map at <console>:26
scala> val result = lower.flatMap(x=>x.trim.split(";"))
result: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[7] at flatMap at <console>:28
scala> result.collect.foreach(println)
bed
chairs
spoon
carpet
curtains
scala> result(0)
<console>:31: error: org.apache.spark.rdd.RDD[String] does not take parameters
result(0)
The results are not trimmed and then passing the index as parameter to get the word at that index gives error. My expected outcome should be as stated below if I pass the index of each word as parameter
result(0)= bed
result(1) = chairs
result(2) = spoon
result(3) = carpet
result(4) = curtains
What am I doing wrong?.
newListUpper2.txt contains (Bed; chairs;spoon; CARPET;curtains )
val file = sc.textFile("myfile.txt")
val lower = file.map(x=>x.toLowerCase)
val result = lower.flatMap(x=>x.trim.split(";")) // x = `bed; chairs;spoon; carpet;curtains` , x.trim does not work. trim func effective for head and tail only
result.collect.foreach(println)
Try it:
val result = lower.flatMap(x=>x.split(";").map(x=>x.trim))
1) Issue 1
scala> result(0)
<console>:31: error: org.apache.spark.rdd.RDD[String] does not take parameters
result is a RDD and it cant take parameters in this format. Instead you can use result.show(10,false)
2) Issue 2 - To achieve like this - result(0)= bed ,result(1) = chairs.....
scala> var result = scala.io.Source.fromFile("/path/to/File").getLines().flatMap(x=>x.split(";").map(x=>x.trim)).toList
result: List[String] = List(Bed, chairs, spoon, CARPET, curtains)
scala> result(0)
res21: String = Bed
scala> result(1)
res22: String = chairs

How to xor char within string and add to List?

In this code where I'm attempting to xor the corresponding characters of two strings :
val s1 = "1c0111001f010100061a024b53535009181c";
val s2 = "686974207468652062756c6c277320657965";
val base64p1 = Base64.getEncoder().encodeToString(new BigInteger(s1, 16).toByteArray())
val base64p2 = Base64.getEncoder().encodeToString(new BigInteger(s2, 16).toByteArray())
val zs : IndexedSeq[(Char, Char)] = base64p1.zip(base64p2);
val xor = zs.foldLeft(List[Char]())((a: List[Char] , b: (Char, Char)) => ((Char)((b._1 ^ b._2))) :: a)
produces error :
Char.type does not take parameters
[error] val xor = zs.foldLeft(List[Char]())((a: List[Char] , b: (Char, Char)) => ((Char)((b._1 ^ b._2))) :: a)
How to xor the corresponding string char values and add them to List ?
What you're doing is can be simplified.
val xor = base64p1.zip(base64p2).map{case (a,b) => (a^b).toChar}.reverse
The result of the XOR op (^) is an Int. Just add .toChar to change it to a Char value.
But it looks like what you really want to do is XOR two large hex values that are represented as strings, and then return the result as a string. To do that all you need is...
val (v1, v2) = (BigInt(s1, 16), BigInt(s2, 16))
f"${v1 ^ v2}%x" // res0: String = 746865206b696420646f6e277420706c6179
You use java casting syntax. In scalla you cast like var.asInstanceOf[Type].
Should be (b._1 ^ b._2).asInstanceOf[Char].

What is the most concise way to increment a variable of type Short in Scala?

I've been working a bit lately on implementing a binary network protocol in Scala. Many of the fields in the packets map naturally to Scala Shorts. I would like to concisely increment a Short variable (not a value). Ideally, I would like something like s += 1 (which works for Ints).
scala> var s = 0:Short
s: Short = 0
scala> s += 1
<console>:9: error: type mismatch;
found : Int
required: Short
s += 1
^
scala> s = s + 1
<console>:8: error: type mismatch;
found : Int
required: Short
s = s + 1
^
scala> s = (s + 1).toShort
s: Short = 1
scala> s = (s + 1.toShort)
<console>:8: error: type mismatch;
found : Int
required: Short
s = (s + 1.toShort)
^
scala> s = (s + 1.toShort).toShort
s: Short = 2
The += operator is not defined on Short, so there appears to be an implicit converting s to an Int preceding the addition. Furthermore Short's + operator returns an Int.
Here's how it works for Ints:
scala> var i = 0
i: Int = 0
scala> i += 1
scala> i
res2: Int = 1
For now I'll go with s = (s + 1).toShort
Any ideas?
You could define an implicit method that will convert the Int to a Short:
scala> var s: Short = 0
s: Short = 0
scala> implicit def toShort(x: Int): Short = x.toShort
toShort: (x: Int)Short
scala> s = s + 1
s: Short = 1
The compiler will use it to make the types match. Note though that implicits also have a shortfall, somewhere you could have a conversion happening without even knowing why, just because the method was imported in the scope, code readability suffers too.

java.lang.Integer cannot be cast to java.lang.Byte error with Any type in Scala

I can cast Int data to Byte.
scala> 10.asInstanceOf[Byte]
res8: Byte = 10
However with the same value in Any type, the cast raises an error.
scala> val x : Any = 10
x: Any = 10
scala> x.asInstanceOf[Byte]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Byte
at scala.runtime.BoxesRunTime.unboxToByte(BoxesRunTime.java:98)
at .<init>(<console>:10)
I can cast twice.
scala> val y = x.asInstanceOf[Int]
y: Int = 10
scala> y.asInstanceOf[Byte]
res11: Byte = 10
Are there better ways than this?
In Scala, compiler tries to hide the distinction between primitive types and reference ones (boxed), defaulting to primitives. Sometimes, abstractions leak and you see that kind of problems.
Here, you're pretending that value is Any, which require compiler to fallback to boxed values:
override def set(value:Any) = {
if (check(value.asInstanceOf[Byte])) {
And here, you're not limiting value to be referential, so such casting will be done on primitive types:
10.asInstanceOf[Byte]
In other words:
scala> val x: Any = 10
x: Any = 10
scala> x.asInstanceOf[Byte]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Byte
at scala.runtime.BoxesRunTime.unboxToByte(BoxesRunTime.java:97)
... 32 elided
scala> val y: Int = 10
y: Int = 10
scala> y.asInstanceOf[Byte]
res4: Byte = 10
To overcome this problem, you probably have to go through an extra conversion to, say, String:
scala> x.toString.toInt
res6: Int = 10
scala> x.toString.toByte
res7: Byte = 10
Try converting to int and then to Byte:
scala> val x : Any = 10
x: Any = 10
scala> x.asInstanceOf[Int].asInstanceOf[Byte]
res1: Byte = 10
Or as IonuČ› G. Stan suggested:
scala> x.asInstanceOf[Int].toByte
res4: Byte = 10
Although I cannot explain why this work.
An integer is 32 bits in Java, while a byte is obviously 8 bits. The problem is what bits do you truncate to make an integer a byte? The least significant 24 bits or the most significant 24 bits? The correct answer is in the context of your problem.

Number formatting in Scala?

I have a dynamically changing input reading from a file. The numbers are either Int or Double. Why does Scala print .0 after every Double number? Is there a way for Scala to print it the same way it reads it?
Example:
var x:Double = 1
println (x) // This prints '1.0', I want it to print '1'
x = 1.0 // This prints '1.0', which is good
I can't use Int because some of the input I get are Doubles. I can't use String or AnyVal because I perform some math operations.
Thank you,
scala> "%1.0f" format 1.0
res3: String = 1
If your input is either Int or Double, you can do it like this:
def fmt(v: Any): String = v match {
case d : Double => "%1.0f" format d
case i : Int => i.toString
case _ => throw new IllegalArgumentException
}
Usage:
scala> fmt(1.0)
res6: String = 1
scala> fmt(1)
res7: String = 1
scala> fmt(1.0f)
java.lang.IllegalArgumentException
at .fmt(<console>:7)
at .<init>(<console>:6)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:4)
at RequestResult$.<clinit>(<console>)
at RequestResult$result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.Dele...
Otherwise, you might use BigDecimals. They are slow, but they do come with the scale, so "1", "1.0" and "1.00" are all different:
scala> var x = BigDecimal("1.0")
x: BigDecimal = 1.0
scala> x = 1
x: BigDecimal = 1
scala> x = 1.0
x: BigDecimal = 1.0
scala> x = 1.000
x: BigDecimal = 1.0
scala> x = "1.000"
x: BigDecimal = 1.000
var x:Double = 1
var y:Double = 1.0
print(x) // => 1.0
print(y) // => 1.0
If i understand you question you want scala to print x and y differently? The problem is that x and y are both a variable of the type Double and look the same.
Why do you explicitly define the type of the vars?
var x = 1
var y= 1.0
print(x) // => 1
print(y) // => 1.0
Use printf:
printf("The value is %.0f", x)
For a description of the format string, see this page from the Java SE 6 API documentation.
Note that you can ofcourse also use the Java library from Scala, so other ways to format numbers from Java can also be used from Scala. You can for example use class java.text.DecimalFormat:
val df = new java.text.DecimalFormat("#####")
println(df.format(x))
Starting with Scala 2.10 you can use the f interpolator:
scala> val x: Double = 1
x: Double = 1.0
scala> println(f"$x%.0f")
1
scala> val i = 1
i: Int = 1
scala> println(f"$i%.0f")
1
The use of a "_.0" at the end of floating point numbers is a convention. Just a way to know that the number is actually floating point and not an integer.
If you really need to "to print it the same way it reads it" you may have to rethink the way your code is structured, possibly preserving your input data. If it's just a formatting issue, the easiest way is to convert the values to integers before printing:
val x = 1.0
println(x.toInt)
If some are integers and some are not, you need a bit more code:
def fmt[T <% math.ScalaNumericConversions](n : T) =
if(n.toInt == n) n.toInt.toString else n.toString
val a : Double = 1.0
val b : Double = 1.5
val c : Int = 1
println(fmt(a))
println(fmt(b))
println(fmt(c))
The code above should print:
1
1.5
1
The signature of the fmt method accepts any type that either is a subtype of ScalaNumericConversions or can be converted to one through implicit conversions (so we can use the toInt method).
If you are working with a Double and want to format it as a String without .0 when it's a whole number and with its decimals otherwise, then you could use String::stripSuffix:
x.toString.stripSuffix(".0")
// val x: Double = 1.34 => "1.34"
// val x: Double = 1.0 => "1"
Use type inference, rather than explicit typing.
scala> val xi = 1
xi: Int = 1
scala> val xd = 1.0
xd: Double = 1.0
scala> println(xi)
1
scala> println(xd)
1.0