在scala中可以为空时整数列表的最小值

时间:2014-02-09 18:39:54

标签: scala typechecking

我试图找到整数列表的最小值,当它可以为空时。

scala> val minValue:Int = List() match {
     |   case Nil => -1
     |   case xs  => xs.min
     | }
<console>:9: error: diverging implicit expansion for type Ordering[B]
starting with method Tuple9 in object Ordering
     case xs => xs.min

虽然它运作良好而非非空列表。

scala> val minValue = List(1,2) match {
     |   case Nil => -1
     |   case xs  => xs.min
     | }
minValue: Int = 1

如何通过排序找到min,我认为是排序并且使用getOrElse defaultValue。

3 个答案:

答案 0 :(得分:3)

问题是类型检查器不知道List()使用什么类型。如果您使用类型专门注释空列表,它应该可以正常工作:

val minValue:Int = List.empty[Int] match { // ...

与@senia讨论后,我意识到你可能使用-1作为“黑客”来说“没有最低限度”而不是实际价值。如果是这种情况,那么在Scala中使用Option类型可能会更清楚,因为您可以返回实际结果的Some变体和空列表中的None变体。 Scala序列实际上已经为你做了一个很好的方法:

scala> List.empty[Int].reduceLeftOption(_ min _)
res0: Option[Int] = None

scala> List(5, 2, 1, 3, 4).reduceLeftOption(_ min _)
res1: Option[Int] = Some(1)

答案 1 :(得分:1)

您的实施是正确的,但您的测试用例不正确:您使用的是List[Nothing]而不是List[Int],请尝试以下操作:

List[Int]() match {
  case Nil => -1;
  case xs => xs.min;
}

// -1

您可以为所有集合添加安全方法:

import scala.collection.GenTraversableOnce

implicit class MinMaxOpt[T](val l: GenTraversableOnce[T]) extends AnyVal {
  def minOpt(implicit o: Ordering[T]) = if (l.isEmpty) None else Some(l.min)
  def minOrElse[T2 >: T](default: T2)(implicit o: Ordering[T]) = minOpt getOrElse default

  def maxOpt(implicit o: Ordering[T]) = if (l.isEmpty) None else Some(l.max)
  def maxOrElse[T2 >: T](default: T2)(implicit o: Ordering[T]) = maxOpt getOrElse default
}

List(1, 2).minOpt
// Some(1)

List[Int]().minOrElse(-1)
// -1

答案 2 :(得分:0)

ScalaDoc中查看List.min的完整签名。

def min[B >: A](implicit cmp: Ordering[B]): A

你看,如果你使用List()没有任何类型提示,它将变成List[Nothing]类型,那么编译器找不到在cmp的位置使用的内容,必须是类型Ordering[B]其中B >: NothingBNothing的超类型。此类型太多, - Nothing是其他所有类型的子类型 - 所以它无法决定使用什么。)