scala – 最小/最大与选项可能是空的Seq?
我正在做一些Scala体操,在那里我尝试着find“最小”的元素。 这就是我现在所做的:
val leastOrNone = seq.reduceOption { (best, current) => if (current.something < best.something) current else best }
它工作正常,但我不是很满意 – 这样一个简单的事情有点长, 我不太在乎“如果” 。 使用minBy
会更加优雅:
val least = seq.minBy(_.something)
…但min
和minBy
在序列为空时抛出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)