I've been learning Scala for a few days with TDD, so I have the following Unit Test:
test("CalcStats.calculateAverage should return average") {
assert(CalcStats.calculateAverage(Array(6, 9, 15, -2, 92, 11)) === 21.833333)
}
As far as I think, the following should make it pass:
def calculateAverage(values: Array[Int]): Float = {
values.sum / values.size
}
However, I am getting 21.0 instead of 21.833333, so the Unit Test will fail ❌
Expected :21.833333
Actual :21.0
As long as I am specifying that the result will be a Float, I thought that was enough, but it is definitely not. What should I do to avoid the truncation in the result?
Thanks in advance.
In
def calculateAverage(values: Array[Int]): Float = {
values.sum / values.size}
underlying result values.sum / values.size has type Int (21)
So, the compiler extend it to Float.
Try the following:
def calculateAverage(values: Array[Int]): Float = {
values.sum.toFloat / values.size }
This method should work - just a simple recursive method to add all the values from the list and, when empty, divide with the total size of the list.
def getAverage(list: List[Double]): Double = {
def loop(list: List[Double], acc: Double = 0): Double = {
list match {
case Nil => acc / list.size
case element :: tail => loop(tail, acc + element)
}
}
loop(list)
}
Related
I want to check if a string is an int, long, float, double or boolean.
For example, "1" should be int, "1.22" should be float and "1.5555555" should be double.
This is the best I've managed:
case item: String =>
if (item.toInt.toString.equals(item)) {
arrayType = Int.getClass
ByteBuffer.allocate(4 * array.length)
}
else if (item.toLong.toString.equals(item)) {
arrayType = Long.getClass
ByteBuffer.allocate(8 * array.length)
}
else if (item.toFloat.toString.equals(item)) {
arrayType = Float.getClass
ByteBuffer.allocate(4 * array.length)
}
else if (item.toDouble.toString.equals(item)) {
arrayType = Double.getClass
ByteBuffer.allocate(8 * array.length)
}
else if (item.toBoolean.toString.equals(item)) {
arrayType = Boolean.getClass
ByteBuffer.allocate(array.length)
}
else throw new UnsupportedOperationException("Type not supported: " + item.getClass)
I don't see how the posted code can work. If item is "true" then .toInt will throw and never get to the .toBoolean test.
I'd be tempted to use RegEx to do the initial segregation and let BigDecimal do the number parsing.
val isBool = "(?i)(?:true|false)".r
val isNum = raw"\d*\.?\d+".r
item match {
case isBool() => ...
case isNum() =>
val bd = BigDecimal(item)
if (bd.isValidInt) ...
else if (bd.isValidLong) ...
else if (bd.isDecimalFloat) ...
else if (bd.isDecimalDouble) ...
else //too big to fit?
case _ => //report bad item
}
The previous answer will work, although it doesn't capture all cases. For example, digits suffixed by f or d can parse into a Double or a Float, as will certain strings like "Infinity" or "-Infinity". As an example, "12.1234567893901f".toFloat -> 12.123457 and "NaN".toFloat -> NaN. Scientific or "E" notation also parses into Floats/Doubles (becoming ±Infinity if needed).
item.getClass will always be String in the line above, so the "Type not supported" error message may be misleading, and you may prefer a IllegalArgumentException with a message that reveals item instead of item.getClass.
Checking s.toXXX.toString.equals(s) won't work for values of s which can successfully parse but are "unsimplified". One case is a long string of digits: "61234817390131412313458".toDouble.toString = "6.123481739013142E22". The same is true of other "unsimplified" values, e.g. "+0".toFloat.toString = "0.0"
As mentioned in comments and previous answers, each toXXX method can throw an error, so to try all of them, they can be wrapped in a Try. The find method of a List will stop on and return the first element that produces isSuccess being true.
If s.toFloat doesn't throw an error, then s.toDouble won't throw an error, and vice versa. Both should succeed or fail together. Therefore, further checks need to be done to see which one is more suitable (but toString.equals is probably too specific as mentioned).
Certain (either very positive or negative) values become ±Infinity when parsed into a float but not double. If an input is forced into Infinity for float but not Double, then you might prefer a Double. If the input parses to Infinity for both types, then choose either type.
Inputs too small will be forced to zero sooner for Float than for Double.
Here's an outline of possible function definitions:
object t {
type Result = (Int, Class[_])
type ListElt = (Result, String => Any)
def useFloat(s:String): Boolean = {
// determine if choosing Float is "desirable"
val floatVal:Float = s.toFloat
val doubleVal:Double = s.toDouble
// if very little precision is lost, or if the maximum information stored isn't lost completely
val MAX_LOST:Double = 1E-5.min(doubleVal)
val preservedPrecision:Boolean = (floatVal - doubleVal).abs <= MAX_LOST
// Remove this variable if `Double` is preferred when bothInfinite
val bothInfinite:Boolean = floatVal.isInfinite && doubleVal.isInfinite
preservedPrecision || bothInfinite
}
def getSizeAndType(s: String): Option[Result] = {
val floatResult:Result = (4, Float.getClass)
val doubleResult:Result = (8, Double.getClass)
val conversions: List[ListElt] = List(
((4, Int.getClass), ((x: String) => x.toInt)),
((8, Long.getClass), ((x: String) => x.toLong)),
(floatResult, ((x: String) => x.toFloat)),
(doubleResult, ((x: String) => x.toDouble)),
((1, Boolean.getClass), ((x: String) => x.toBoolean))
)
val firstSuccess: Option[ListElt] = conversions.find((elt: ListElt) => scala.util.Try(elt._2(s)).isSuccess)
val result = firstSuccess.map(_._1)
// check if choosing Float is "desirable"
result match {
case Some(`floatResult`) =>
if (useFloat(s)){
Some(floatResult)
} else {
Some(doubleResult)
}
case other => other
}
}
def handle(s:String) = {
val (bytes, arrayType) = getSizeAndType(s).getOrElse(0, "None")
if (bytes > 0) {
// perform allocation
//ByteBuffer.allocate(4 * array.length)
println(s"${bytes}, ${arrayType}")
} else {
// throw exception, etc.
println("Not parsable")
}
}
}
println(t.handle("9")) // 4, class scala.Int$
println(t.handle("1.9")) // 4, class scala.Float$
println(t.handle("2147483648")) // 8, class scala.Long$
println(t.handle("2.5769803776E9")) // 8, class scala.Double$ (small enough for finite float but loses enough precision)
println(t.handle("3.4028235E38")) // 8, class scala.Double$ (ditto)
println(t.handle("6.805647E38")) // 8, class scala.Double$ (too big for finite float)
println(t.handle("12.123456789")) // 4, class scala.Float$
println(t.handle("Infinity")) // 4, class scala.Float$
println(t.handle("false")) // 1, class scala.Boolean$
println(t.handle("xyz")) // Not parsable
I came up with the following to convert a List[Int] => Try[BigDecimal]:
import scala.util.Try
def f(xs: List[Int]): Try[BigDecimal] =
Try { xs.mkString.toInt }.map ( BigDecimal(_) )
Example:
scala> f(List(1,2,3,4))
res4: scala.util.Try[BigDecimal] = Success(1234)
scala> f(List(1,2,3,55555))
res5: scala.util.Try[BigDecimal] = Success(12355555)
Is there a way to write this function without resorting to a String conversion step?
Not very pretty, and I'm not convinced it's much more efficient. Here's the basic outline.
val pwrs:Stream[BigInt] = 10 #:: pwrs.map(_ * 10)
List(1,2,3,55555).foldLeft(0:BigInt)((p,i) => pwrs.find(_ > i).get * p + i)
Here it is a little more fleshed out with error handling.
import scala.util.Try
def f(xs: List[Int]): Try[BigDecimal] = Try {
lazy val pwrs: Stream[BigDecimal] = 10 #:: pwrs.map(_ * 10)
xs.foldLeft(0: BigDecimal) {
case (acc, i) if i >= 0 => pwrs.find(_ > i).get * acc + i
case _ => throw new Error("bad")
}
}
UPDATE
Just for giggles, I thought I'd plug some code into Rex Kerr's handy benchmarking/profiling tool, Thyme.
the code
import scala.util.Try
def fString(xs: List[Int]): Try[BigInt] = Try { BigInt(xs.mkString) }
def fStream(xs: List[Int]): Try[BigInt] = Try {
lazy val pwrs: Stream[BigInt] = 10 #:: pwrs.map(_ * 10)
xs.foldLeft(0: BigInt) {
case (acc, i) if i >= 0 => pwrs.find(_ > i).get * acc + i
case _ => throw new Error("bad")
}
}
def fLog10(xs: List[Int]): Try[BigInt] = Try {
xs.foldLeft(0: BigInt) {
case (acc, i) if i >= 0 =>
math.pow(10, math.ceil(math.log10(i))).toInt * acc + i
case _ => throw new Error("bad")
}
}
fString() is a slight simplification of Kevin's original question. fStream() is my proposed non-string implementation. fLog10 is the same but with Alexey's suggested enhancement.
You'll note that I'm using BigInt instead of BigDecimal. I found that both non-string methods encountered a bug somewhere around the 37th digit of the result. Some kind of rounding error or something, but there was no problem with BigInt so that's what I used.
test setup
// create a List of 40 Ints and check its contents
val lst = List.fill(40)(util.Random.nextInt(20000))
lst.min // 5
lst.max // 19858
lst.mkString.length // 170
val th = ichi.bench.Thyme.warmed(verbose = print)
th.pbenchWarm(th.Warm(fString(lst)), title="fString")
th.pbenchWarm(th.Warm(fStream(lst)), title="fStream")
th.pbenchWarm(th.Warm(fLog10(lst)), title="fLog10")
results
Benchmark for fString (20 calls in 345.6 ms) Time: 4.015 us 95%
CI 3.957 us - 4.073 us (n=19) Garbage: 109.9 ns (n=2 sweeps
measured)
Benchmark for fStream (20 calls in 305.6 ms) Time: 7.118 us 95%
CI 7.024 us - 7.213 us (n=19) Garbage: 293.0 ns (n=3 sweeps
measured)
Benchmark for fLog10 (20 calls in 382.8 ms) Time: 9.205 us 95%
CI 9.187 us - 9.222 us (n=17) Garbage: 73.24 ns (n=2 sweeps
measured)
So I was right about the efficiency of the non-string algorithm. Oddly, using math._ to avoid Stream creation doesn't appear to be better. I didn't expect that.
takeaway
Number-to-string and string-to-number transitions are reasonably efficient.
import scala.util.{Try, Success}
import scala.annotation.tailrec
def findOrder(i: Int): Long = {
#tailrec
def _findOrder(i: Int, order: Long): Long = {
if (i < order) order
else _findOrder(i, order * 10)
}
_findOrder(i, 1)
}
def f(xs: List[Int]): Try[BigDecimal] = Try(
xs.foldLeft(BigDecimal(0))((acc, i) => acc * findOrder(i) + i)
)
To find the correct power of 10 more efficiently (replace pwrs.find(_ > i).get with nextPowerOf10(i) in #jwvh's answer):
def nextPowerOf10(x: Int) = {
val n = math.ceil(math.log10(x))
BigDecimal(math.pow(10, n))
}
Since you start with an Int, there should be no rounding issues.
Below is a simple 'repeat' method I am trying to write using tail recursion. The sole purpose of this function is to just repeat the giving string back to back 'n' amount of times.
I.e. repeat("Hello",3) = "HelloHelloHello"
But for whatever reason I am getting a 'java.lang.UnsupportedOperationException' and I am not sure why.
P.S. This is a homework assignment so if I could just be pointed in the right direction instead of a straight answer that would be cool!
def repeat(s: String, n: Int): String = {
def tailRepeat(str: String, x: Int): String = x match {
case `n` => str
case _ => val repeatString = s + str
tailRepeat(repeatString, (x + 1))
}
tailRepeat(s, 0)
}
I think you are making this a little too complex. For one thing you don't really need pattern matching at all, you have a counting variable that tells you how many times to repeat your string, using that would simplify your code greatly. Also it is usually more straightforward to count down and not up:
def repeat(s: String, n: Int): String = {
def tailRepeat(str: String, x: Int): String = {
if(x == 0) str
else tailRepeat(str + s, x - 1)
}
tailRepeat(s, n - 1)
}
println( repeat("hello", 3) );
// hellohellohello
I'm newbie in using Scala, and most of the time I don't know how to deal with error messages. Can someone help me with this code? What do I need to change to make this code work? Btw, I'm writing Euklid's Greatest Common Divisor in Scala.
def userInput() {
var x: String = Console.readLine("Please enter the first number you want to calculate. ")
var y: String = Console.readLine("Please enter the second number you want to calculate. ")
println(userInput())
}
def ggt(firstNumber: Long, secondNumber: Long): Long = {
var x = firstNumber
var y = secondNumber
if (y == 0) {
return x
}
}
And the error I get is "type mismatch; found : Unit required: Long" in this line:
if (y == 0) {
What should I change? Thanks in advance for your guys help!
Your ggt function needs to return a Long and it's not always doing so. First, you can remove the return keyword because scala functions will always return whatever is on the last line. Then, you need a return value when y != 0 to make this function definition valid. Right now, it's returning Unit which is like void because there is no else block there. Change to something like this and you should be all set:
def ggt(firstNumber: Long, secondNumber: Long): Long = {
var x = firstNumber
var y = secondNumber
if (y == 0) x
else y
}
First, if you want to read numbers from the command line, then your userInput is incorrect, it should be something like this:
def readNumbers(): (Long, Long) = {
println("Print the first number")
val first = Console.readLong()
println("Println the seconds number")
val second = Console.readLong()
(first, second)
}
Then read numbers:
val (a, b) = readNumbers()
GCD method:
def gcd(a: Long, b: Long): Long = if (b == 0) a else gcd(b, a % b)
and call it on the numbers:
gcd(a, b)
Scala is a functional on the one hand, so every expression results in some value, and in Scala if is an expression, not a statement.
I just start learning scala. I got an error "illegal start of simple expression" in eclipse while trying to implement a recursive function:
def foo(total: Int, nums: List[Int]):
if(total % nums.sorted.head != 0)
0
else
recur(total, nums.sorted.reverse, 0)
def recur(total: Int, nums: List[Int], index: Int): Int =
var sum = 0 // ***** This line complained "illegal start of simple expression"
// ... other codes unrelated to the question. A return value is included.
Can anyone tell me what I did wrong about defining a variable inside a (recursive) function? I did a search online but can't one explains this error.
A variable declaration (var) doesn't return a value, so you need to return a value somehow, here's how the code could look like:
object Main {
def foo(total: Int, coins: List[Int]): Int = {
if (total % coins.sorted.head != 0)
0
else
recur(total, coins.sorted.reverse, 0)
def recur(total: Int, coins: List[Int], index: Int): Int = {
var sum = 0
sum
}
}
}
The indentation seems to imply that recur is inside count, but since you did not place { and } surrounding it, count is just the if-else, and recur is just the var (which is illegal -- you have to return something).
I had a similar problem where I was doing something like
nums.map(num =>
val anotherNum = num + 1
anotherNum
)
and the way to fix it was to add curly braces:
nums.map { num =>
val anotherNum = num + 1
anotherNum
}
I thought these expressions were equivalent in Scala, but I guess I was wrong.
I had a similar problem. Found example 8.1 in the book that looked like:
object LongLines {
def processFile(filename: String, width: Int) **{**
val source = Source.fromFile(filename)
for (line <- source.getLines)
processLine(filename, width, line)
**}**
Note: the "def processFile(filename: String, width: Int) {" and ending "}"
I surrounded the 'method' body with {} and scala compiled it with no error messages.