3

I'd like to adapt this code as given here : Find min and max elements of array

def minMax(a: Array[Int]) : (Int, Int) = {
  if (a.isEmpty) throw new java.lang.UnsupportedOperationException("array is empty")
  a.foldLeft((a(0), a(0)))
  { case ((min, max), e) => (math.min(min, e), math.max(max, e))}
}

To work also with Long, Float and Double (since these are the types accepted by scala.math.min/max. I tried:

def getMinAndMax[@specialized(Int,Long,Float,Double) T](x: Seq[T]) : (T, T) = {
  if (x.isEmpty) throw new java.lang.UnsupportedOperationException("seq is empty")
  x.foldLeft((x.head, x.head))
  { case ((min, max), e) => (math.min(min, e), math.max(max, e))}
}

But this does not compile either. Any advice?

Raphael Roth
  • 26,751
  • 15
  • 88
  • 145

2 Answers2

5

You want a typeclass. Specifically, in this case, you want Ordering from the stdlib.

// It is more idiomatic to return an Option rather than throwing an exception,
// that way callers may decide how to handle that case.
def getMinAndMax[T : Ordering](data: IterableOnce[T]): Option[(T, T)] = {
  import Ordering.Implicits._ // Provides the comparison operators: < & >

  data.iterator.foldLeft(Option.empty[(T, T)]) {
    case (None, t) =>
      Some((t, t))
    
    case (current @ Some((min, max)), t) =>
      if (t < min) Some((t, max))
      else if (t > max) Some((min, t))
      else current
  }
}

You can see the code running here.

1

Another approach would be to use min/max from Numeric :

def minMax[T](s: Seq[T])(implicit num: Numeric[T]): (T, T) = {
    if (s.isEmpty) throw new java.lang.UnsupportedOperationException("seq is empty")
    s.foldLeft((s.head, s.head)) {case ((min, max), e) => (num.min(min, e), num.max(max, e))}
  }
Raphael Roth
  • 26,751
  • 15
  • 88
  • 145