scala – 最小/最大与选项可能是空的Seq?

我正在做一些Scala体操,在那里我尝试着find“最小”的元素。 这就是我现在所做的:

 val leastOrNone = seq.reduceOption { (best, current) => if (current.something < best.something) current else best } 

它工作正常,但我不是很满意 – 这样一个简单的事情有点长, 我不太在乎“如果” 。 使用minBy会更加优雅:

 val least = seq.minBy(_.something) 

…但minminBy在序列为空时抛出exception。 有没有一种习惯的,更优雅的方式find一个可能的空列表中最小的元素作为一个Option

 seq.reduceOption(_ min _) 

做你想要的?


编辑:这是一个例子合并你的_.something

 case class Foo(a: Int, b: Int) val seq = Seq(Foo(1,1),Foo(2,0),Foo(0,3)) val ord = Ordering.by((_: Foo).b) seq.reduceOption(ord.min) //Option[Foo] = Some(Foo(2,0)) 

或者,作为一般的方法:

 def minOptionBy[A, B: Ordering](seq: Seq[A])(f: A => B) = seq reduceOption Ordering.by(f).min 

你可以调用minOptionBy(seq)(_.something)

与Scalaz一个安全,紧凑和O(n)版本:

 xs.nonEmpty option xs.minBy(_.foo) 

由于O(nlogn)复杂性,几乎没有select大的列表:

 seq.sortBy(_.something).headOption 

Scala允许我们用Try来捕获错误。 我们来写一个使用它的函数:

 def min[T <% Ordered[T]](s: Seq[T]) = util.Try(s.min).toOption 

现在我们来testing一下:

 scala> min(Seq(1,2,3)) res4: Option[Int] = Some(1) scala> min(Seq.empty[Int]) res5: Option[Int] = None 

这个怎么样?

 import util.control.Exception._ allCatch opt seq.minBy(_.something) 

或者,更详细地说,如果你不想吞下其他例外:

 catching(classOf[UnsupportedOperationException]) opt seq.minBy(_.something) 

或者,你可以像这样用所有的集合皮条客:

 import collection._ class TraversableOnceExt[CC, A](coll: CC, asTraversable: CC => TraversableOnce[A]) { def minOption(implicit cmp: Ordering[A]): Option[A] = { val trav = asTraversable(coll) if (trav.isEmpty) None else Some(trav.min) } def minOptionBy[B](f: A => B)(implicit cmp: Ordering[B]): Option[A] = { val trav = asTraversable(coll) if (trav.isEmpty) None else Some(trav.minBy(f)) } } implicit def extendTraversable[A, C[A] <: TraversableOnce[A]](coll: C[A]): TraversableOnceExt[C[A], A] = new TraversableOnceExt[C[A], A](coll, identity) implicit def extendStringTraversable(string: String): TraversableOnceExt[String, Char] = new TraversableOnceExt[String, Char](string, implicitly) implicit def extendArrayTraversable[A](array: Array[A]): TraversableOnceExt[Array[A], A] = new TraversableOnceExt[Array[A], A](array, implicitly) 

然后只需写seq.minOptionBy(_.something)

我以前有同样的问题,所以我扩展Ordered并实现比较function。 这里是例子:

  case class Point(longitude0: String, latitude0: String) extends Ordered [Point]{ def this(point: Point) = this(point.original_longitude,point.original_latitude) val original_longitude = longitude0 val original_latitude = latitude0 val longitude = parseDouble(longitude0).get val latitude = parseDouble(latitude0).get override def toString: String = "longitude: " +original_longitude +", latitude: "+ original_latitude def parseDouble(s: String): Option[Double] = try { Some(s.toDouble) } catch { case _ => None } def distance(other: Point): Double = sqrt(pow(longitude - other.longitude, 2) + pow(latitude - other.latitude, 2)) override def compare(that: Point): Int = { if (longitude < that.longitude) return -1 else if (longitude == that.longitude && latitude < that.latitude) return -1 else return 1 } } 

所以如果我有一个seq的点我可以要求最大或最小的方法

  var points = Seq[Point]() val maxPoint = points.max val minPoint = points.min 

在Haskell中,你minimumBy调用包装为

 least fx | Seq.null x = Nothing | otherwise = Just (Seq.minimumBy fx)