Setting number of decimals in formatting programmatically - scala

I have the following Double in Scala:
val value: Double = 12.34
and get the formatted value, like so:
val formatted = f"$value%1.5f"
But I need to set the number of decimals (above 5) programmatically. I tried this, but it doesn't work:
val dec = 8
val formatted = f"$value%1.decf"
Any ideas?

val value: Double = 12.34
val dec = 8
val formatted = s"%1.${dec}f".format(value) // 12.34000000

You can use the scala BigDecimal with its setScale def then convert to a Double if necessary:
BigDecimal(12.35564126).setScale(5, BigDecimal.RoundingMode.HALF_UP).toDouble
// res0: Double = 12.35564

How about
fmt="%."+n+"f"
fmt.format(12.34)
Too obvious?

Related

Format double with variable decimal precision

I know that for in Scala.js (cannot use java.text.DecimalFormat) I can write this:
val number = 1.2345
println(f"$x%.2f") // "1.23"
However, this doesn't seem to work:
val decimalPlaces = 2
println(f"$x%.${decimalPlaces}f")
// [error] Missing conversion operator in '%'; use %% for literal %, %n for newline f"$x%.${decimalPlaces}f"
// also doesn't work: (f"$x%." + decimalPlaces + "f").toFloat
How can I achieve a variable decimal precision?
This works
val number = 1.2345
val decimalPlaces = 2
println(("%." + decimalPlaces + "f").format(number))
There is an implicit call to StringLike for format.
I suppose the reason it doesn't work is that nowhere in the expression:
s"$number%.$decimalPlacesf" # DOESN'T WORK
we are providing the order on how should the variables be resolved.
You need to artificially enforce it. Similarly to #nattyddubbs's answer:
val number = 1.2345
val decimalPlaces = 3
val format = s"%.${decimalPlaces}f"
println(format.format(number)) # 1.235

How to use split function in spark scala

I am supplying line by line to the program and each line consists of date in the format MM/DD/YYYY, how I can use split function here.
val data = line.split("/")
val year = data[2]
println(year)
I am not getting any output can anyone explain me where I am wrong.
You are not working on Java. Please look at the code snippet and make required changes in your code.
scala> val str = "12/05/2018"
str: String = 12/05/2018
scala> str.split("/")
res0: Array[String] = Array(12, 05, 2018)
scala> res0(2)
res1: String = 2018
So make below changes in your code:
val data = line.split("/")
val year = data(2)
println(year)

Cannot convert string to a long in scala

Why can I not convert the following string into a long? i am trying to do this in scala.
var a = "153978017952566571852"
val b = a.toLong
when I try to convert it I get the NumberFormatException
Because the number exceeds the limit of Long Integer which goes from -9223372036854775808 to 9223372036854775807, with maximum of 19 digits, while your string contains 21 digits.
You can convert it to Float or Double if you don't have to be exact:
scala> val b = a.toFloat
b: Float = 1.5397802E20
scala> val b = a.toDouble
b: Double = 1.5397801795256658E20

How do I format numbers as percentages in Scala?

What is the simplest/idiomatic way to format percentages in Scala?
I have the following solution but I'm wondering if a more concise way exists:
val value = 0.1456
val s1 = f"the float value is ${value}%.2f"
val s2= s"the percent value is ${java.text.NumberFormat.getPercentInstance.format(value)}"
value: Double = 0.1456
s1: String = the float value is 0.15
s2: String = the percent value is 15%
If you are looking for more of a concise method, the following works and goes along with your initial idea in your code. It is also easy to add on decimal placement without having to resort to the implicit functionality. Obviously these needs to be used a lot a better solution is with the implicit method.
val value = 0.1456
val s2 = val s2 = f"the percent value is ${value*100}%.0f%%"
s2: String = the percent value is 15%
just to give a couple of other runs as well (t show rounding down here):
val value2 = 0.1416
val s3 = val s2 = f"the percent value is ${value2*100}%.0f%%"
s3: String = the percent value is 14%
Example to show adding decimal places:
val s4 = f"the percent value is ${value2*100}%.1f%%"
s4: String = the percent value is 14.2%
You could use the "pimp my library" pattern to add the asPercentage method to Doubles.
implicit class DoubleAsPercentage(d: Double) {
def asPercentage = java.text.NumberFormat.getPercentInstance.format(d)
}
val s2 = s"the percent value is ${value.asPercentage}"
You can use the f string to format the percentage to the relevant decimal places you wish. In this example, it has 4 decimal places however if you only want to return two decimal places, then use .2f in the string below.
To return 3 decimal places, then use .3f etc etc. However if you want more decimal places than suggested; "here they are 4", you will end up with trailing zeros.
val percentage = 51.9938
scala> f"I scored $percentage%.8f%% in my exams"
res164: String = I scored 51.99380000% in my exams
scala> f"I scored $percentage%.2f%% in my exams"
res165: String = I scored 51.99% in my exams

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