1
votes

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?

2

2 Answers

3
votes

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 Ts 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.

0
votes

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