Reputation: 352
I'm trying to get the minimum and maximum values in a list of ordered numbers. There is no problem when working with specific type:
private def minMaxValue (valuesList: List[Option[Int]], min: Boolean): Option[Int] =
valuesList.flatten match {
case Nil => None
case xs => Some(if (min) xs.min else xs.max)
}
but when I can't find the way to change it to also accept Long and Float, I tried:
private def minMaxValue (valuesList: List[Option[Any]], min: Boolean): Option[Int] =
valuesList.flatten match {
case Nil => None
case xs: List[Int] => Some(if (min) xs.min else xs.max)
case xs: List[Long] => Some(if (min) xs.min else xs.max)
}
but it doesn't work and I get this warning for
- non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure
What is the best way to solve this in scala?
Upvotes: 2
Views: 1775
Reputation: 33379
I would do it like this:
def minMaxValue[T <% Ordered[T]](valuesList: List[Option[T]], min: Boolean): Option[T] =
valuesList.flatten match {
case Nil => None
case xs => Some(if (min) xs.min else xs.max)
}
This creates a generic function with a type parameter T
. You have to declare that T
is an ordered type, so the compiler can prove that a collection of T
s has min
and max
methods.
It works well for ints and doubles:
scala> minMaxValue(List(Option(1), None, Option(3)), false)
res7: Option[Int] = Some(3)
scala> minMaxValue(List(Option(1.0), None, Option(3.0)), false)
res8: Option[Double] = Some(3.0)
scala> minMaxValue(List(Option(1.0), None, Option(3.0)), true)
res9: Option[Double] = Some(1.0)
The thing with type erasure in the JVM is that type parameters are available only at compile time but not at runtime. In my solution, the compiler sees the type T
and can use that information for type checking and for generating a function that works for the specific value of T
that you are using. In your code, you need to tell if something is a List[Int]
or a List[Long]
at runtime, but that information is already erased by then.
Upvotes: 4
Reputation: 2804
I would transform the List[Option[Int]]
to a List[Int]
to be able to use the max
and min
methods.
val listOpt = List(Some(3), None, Some(7))
val listValues = listOpt.collect{
case Some(x) => x
}
listValues.max
listValues.min
Upvotes: 0