How to implement generic average function in scala? - scala

It seems easy problem for any specific kind of Number i.e. Double/Integer but it is hard to write in general case.
implicit def iterebleWithAvg(data:Iterable[Double]) = new {
def avg:Double = data.sum / data.size
}
How to implement this for any kind of Number(Int,Float,Double,BigDecemial)?

You have to pass an implicit Numeric which will allow summation and conversion to Double:
def average[T]( ts: Iterable[T] )( implicit num: Numeric[T] ) = {
num.toDouble( ts.sum ) / ts.size
}
The compiler will provide the correct instance for you:
scala> average( List( 1,2,3,4) )
res8: Double = 2.5
scala> average( 0.1 to 1.1 by 0.05 )
res9: Double = 0.6000000000000001
scala> average( Set( BigInt(120), BigInt(1200) ) )
res10: Double = 660.0
You can the use the function to define an implicit view (provided you propagate the implicit numeric dependency):
implicit def iterebleWithAvg[T:Numeric](data:Iterable[T]) = new {
def avg = average(data)
}
scala> List(1,2,3,4).avg
res13: Double = 2.5

Here's the way I define it in my code.
Instead of using Numeric, I use Fractional, since Fractional defines a division operation (Numeric doesn't necessarily have division). This means that when you call .avg, you will get back the same type you put in, instead of always getting Double.
I also define it over all GenTraversableOnce collections so that it works on, for example, Iterator.
class EnrichedAvgFractional[A](self: GenTraversableOnce[A]) {
def avg(implicit num: Fractional[A]) = {
val (total, count) = self.toIterator.foldLeft((num.zero, num.zero)) {
case ((total, count), x) => (num.plus(total, x), num.plus(count, num.one))
}
num.div(total, count)
}
}
implicit def enrichAvgFractional[A: Fractional](self: GenTraversableOnce[A]) = new EnrichedAvgFractional(self)
Notice how if we give it a collection of Double, we get back Double and if we give it BigDecimal, we get back BigDecimal. We could even define our own Fractional number type (which I do occasionally), and it will work for that.
scala> Iterator(1.0, 2.0, 3.0, 4.0, 5.0).avg
res0: Double = 3.0
scala> Iterator(1.0, 2.0, 3.0, 4.0, 5.0).map(BigDecimal(_)).avg
res1: scala.math.BigDecimal = 3.0
However, Int is not a kind of Fractional, meaning that it doesn't make sense to get an Int and the result of averaging Ints, so we have to have a special case for Int that converts to a Double.
class EnrichedAvgInt(self: GenTraversableOnce[Int]) {
def avg = {
val (total, count) = self.toIterator.foldLeft(0, 0) {
case ((total, count), x) => (total + x, count + 1)
}
total.toDouble / count
}
}
implicit def enrichAvgInt(self: GenTraversableOnce[Int]) = new EnrichedAvgInt(self)
So averaging Ints gives us a Double:
scala> Iterator(1, 2, 3, 4, 5).avg
res2: Double = 3

Related

Convert Any to Double using asInstanceOf?

Is there a supported way to achieve a conversion of any numeric type to a double. E.g.
val i = 12345
val f = 1234.5F
val d = 1234.5D
val arr = Array[Any](i,f,d)
val anotherD = arr(0).asInstanceOf[Numeric].toDouble
Naturally the above code is not correct as given - since Numeric requires Type arguments.
scala> val i = 12345
i: Int = 12345
scala> val f = 1234.5F
f: Float = 1234.5
scala> val d = 1234.5D
d: Double = 1234.5
scala> val arr = Array[Any](i,f,d)
arr: Array[Any] = Array(12345, 1234.5, 1234.5)
scala> val anotherD = arr(0).asInstanceOf[Numeric].toDouble
<console>:11: error: type Numeric takes type parameters
val anotherD = arr(0).asInstanceOf[Numeric].toDouble
Now I realize the above may be achieved via match/case , along the following lines:
(a, e) match {
case (a : Double, e : Double) =>
Math.abs(a - e) <= CompareTol
case (a : Float, e : Float) =>
Math.abs(a - e) <= CompareTol
.. etc
But I was wondering if there were a means to more compactly express the operation. This code is within TEST classes and efficiency is not an important criterion. Specifically: reflection calls are OK. Thanks.
I assume you are on the JVM. The Number class does like what you want to achieve with the doubleValue method:
val arr = Array[Number](i,f,d)
val ds = arr.map(_.doubleValue())
This is horrible, and probably not efficient, but it works (on your example) :p
scala> import scala.language.reflectiveCalls
import scala.language.reflectiveCalls
scala> arr.map(_.asInstanceOf[{ def toDouble: Double }].toDouble)
res2: Array[Double] = Array(12345.0, 1234.5, 1234.5)

Using asInstanceOf to convert Any to Double

I have a function that takes a variable number of arguments. The first is a String and the rest are numbers (either Int or Double) so I am using Any* to get the arguments. I would like to treat the numbers uniformly as Doubles, but I cannot just use asInstanceOf[Double] on the numeric arguments. For example:
val arr = Array("varargs list of numbers", 3, 4.2, 5)
val d = arr(1).asInstanceOf[Double]
gives:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
Is there a way to do this? (The function needs to add up all the numbers).
Scala's asInstanceOf is its name for casting. Casting is not converting.
What you want can be accomplished like this:
val mongrel = List("comment", 1, 4.0f, 9.00d)
val nums = mongrel collect { case i: Int => i case f: Float => f case d: Double => d }
val sumOfNums = nums.foldLeft(0.0) ((sum, num) => sum + num)
Here is a slight simplification of Randall's answer:
val mongrel = List("comment", 1, 4.0f, 9.00d)
val nums = mongrel collect { case i: java.lang.Number => i.doubleValue() }
val sumOfNums = nums.sum
Matching for any kind of number turns out to be a little tricky in Scala, see here for another way of doing it.
When there is a need to handle different types, you should avoid casting them and instead use a pattern match. To add up all Double's and Int's of an array you could use:
val array = Array("varargs list of numbers", 3, 4.2, 5)
array.foldLeft(0.0){
case (s, i: Int) => s + i
case (s, d: Double) => s + d
case (s, _) => s
}
The pattern match allows you to treat each different type separately and avoids running into ClassCastExceptions.
Stepping back for a moment, might it be easier to have the function take Double* instead of Any*?
scala> def foo(str: String, nums: Double*) {
nums foreach { n => println(s"num: $n, class: ${n.getClass}") }
}
foo: (str: String, nums: Double*)Unit
scala> foo("", 1, 2.3)
num: 1.0, class: double
num: 2.3, class: double

Extracting a value from an option inside an option in Scala

Given the following:
val x = Some(Some(1))
What would be the cleanest way to get the 1 (or -1 if the one did not exist)?
I'm creating an object instance from a tuple returned from a database query. One of the values in the tuple looks like this, so I would like a nice short 'one liner' to just get the value or set a parameter to -1.
x.flatten is what you are looking for. Here it will give you Some(1).
If you really want to get -1 for the case where "the one did not exist", just do x.flatten.getOrElse(-1):
scala> Some(Some(1)).flatten.getOrElse(-1)
res1: Int = 1
scala> Some(None).flatten.getOrElse(-1)
res2: Int = -1
scala> None.flatten.getOrElse(-1)
res3: Int = -1
for-comprehensions are often a very readable way to use these kinds of nested structures:
val x = Some(Some(1))
val result = for {
firstLevel <- x
secondLevel <- firstLevel
} yield {
// We've got an int, now transform it!
(secondLevel * 100).toString
}
The result is an Option[String], and the transformation only happens when you have two Some(s).
You can also use pattern matching:
val result2 = for {
Some(v) <- x
} yield {
// We've got a int, now transform it!
(v * 100).toString
}
Although not a "one-liner" you could make a function to extract the value. If you make it generic and pass in the default value it might be pretty handy.
scala> def fetchFromOptions[A](default: A)(x: Option[Option[A]]) = x match {
| case Some(Some(a)) => a
| case _ => default
| }
fetchFromOptions: [A](default: A)(x: Option[Option[A]])A
scala> fetchFromOptions(-1)(Some(Some(1)))
res0: Int = 1
scala> fetchFromOptions(-1)(Some(None))
res1: Int = -1
This is what I've come up with:
scala> val x = Some(Some(1))
x: Some[Some[Int]] = Some(Some(1))
scala> val y = x.map(_.getOrElse(-1)).get
y: Int = 1
scala> val x = Some(None)
x: Some[None.type] = Some(None)
scala> val y = x.map(_.getOrElse(-1)).get
y: Int = -1
This only works when your first-level Some is not None
If you actually know that its Some(Some(1)), then you can use the irrefutable pattern match notation:
scala> val ssi1 = Some(Some(1))
ssi1: Some[Some[Int]] = Some(Some(1))
scala> val Some(Some(i1)) = ssi1
i1: Int = 1
If there may be any of the possible None in the mix, then you have to use the more cautious and verbose forms suggested by others.
For those that find this a bizarre notation, think of it as what you'd write in a case in a match construct or PartialFunction literal to match against a scrutinee that is Some(Some(1)).

Scala: return reference to a function

I'd like to have a Scala functions that returns the reference to another function, is that possible?
You can return a function type (this is defined by A => B). In this case Int to Int:
scala> def f(x:Int): Int => Int = { n:Int => x + n }
f: (x: Int)(Int) => Int
When you call the function you get a new function.
scala> f(2)
res1: (Int) => Int = <function1>
Which can be called as a normal function:
scala> res1(3)
res2: Int = 5
One way (somewhat unique to functional object-orientation) you can use higher order functions is to create loose couplings between objects.
In the example below the class Alarm has a method check4Danger() that checks if a calculated value exceeds the DangerLevel. The Alarm class does not know anything about the objects that call it.
The Car class has a method engineCrashRisk() that returns an anonymous function that calculate the risk of engine crash. Car does not have dependency to Alarm.
case class Alarm(temperature: Double, pressure: Double){
val DangerLevel = 100000.0
def check4Danger( f: (Double, Double) => Double): Boolean = {
val risk = f(temperature, pressure)
if( risk > DangerLevel ){
println("DANGER: "+ risk )
true
}else{
println("Safe: " + risk)
false
}
}
}
case class Car(fuelRate: Double, milage: Int){
def engineCrashRisk() =
(temperature: Double, pressure: Double) =>
temperature * milage + 2*pressure / fuelRate
}
val car = Car(0.29, 123)
val riskFunc = car.engineCrashRisk
val alarm = Alarm(124, 243)
val risk = alarm.check4Danger(riskFunc)
The output of this script is:
Safe: 16927.862068965518
In this example we used anonymous functions with closures to create a dependency free method call between the Alarm and Car objects. Does this example make any sense?

scala way to define functions accepting a List of different numeric types

I have the following problem: I have a function which takes a List[Double] as parameter, performs some arithmetic operations on the elements of the list and than return the result. I would like the function also to accept List[Int]. Here is an example:
def f(l: List[Double]) = {
var s = 0.0
for (i <- l)
s += i
s
}
val l1 = List(1.0, 2.0, 3.0)
val l2 = List(1, 2, 3)
println(f(l1))
println(f(l2))
Of course the second println fails since f requires List[Double] and not List[Int].
Also note the non scala style formulation of the sum within the f function in order to evidence the need to use 0 (or other constants) within the function itself (if i sum Int values I have to init s to 0 not 0.0.
Which is the best way (less code) to get the function work on both Double and Int?
(I have seen something about 2.8 Numeric trait by I'm not so sure how to use it...)
Thanks everybody for the help.
With scala 2.8 and using Numeric combine to implicit conversion your example could be written as :
import Numeric._
def f[T](l: List[T])(implicit n: Numeric[T]):T = {
var s = n.zero
for (i <- l)
s = n.plus(s, i)
s
}
val l1 = List(1.0, 2.0, 3.0)
val l2 = List(1, 2, 3)
println(f(l1))
println(f(l2))
//or
def f2[T](l: List[T])(implicit n: Numeric[T]):T = {
import n._
var s = zero
for (i <- l)
s += i
s
}
println(f2(l1))
println(f2(l2))
Now another example doing the sum in a more scala way:
def sum[T](l:List[T])(implicit n: Numeric[T]):T = {
import n._
l.foldLeft(zero)(_ + _)
}
println(sum(l1))
println(sum(l2))
//or since 2.8 Seq include already a sum function
def sum[T](l:List[T])(implicit n: Numeric[T]):T = l.sum
println(sum(l1))
println(sum(l2))
This answer uses the Numeric trait.
import Numeric._
def f[A](l: List[A])(implicit numeric: Numeric[A]) =
l reduceLeft ((l,r) => numeric.plus(l, r))
Or using context bounds:
def f[A : Numeric](l: List[A]) =
l.reduceLeft((l,r) => implicitly[Numeric[A]].plus(l, r))