scala 对于可能为空的 Seq,使用 Option[T] 的最小值/最大值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10922237/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Min/max with Option[T] for possibly empty Seq?
提问by gustafc
I'm doing a bit of Scala gymnastics where I have Seq[T]in which I try to find the "smallest" element. This is what I do right now:
我正在做一些 Scala 体操,Seq[T]在那里我试图找到“最小”元素。这就是我现在所做的:
val leastOrNone = seq.reduceOption { (best, current) =>
if (current.something < best.something) current
else best
}
It works fine, but I'm not quite satisfied - it's a bit long for such a simple thing, and I don't care much for "if"s. Using minBywould be much more elegant:
它工作正常,但我不太满意 - 这么简单的事情有点长,而且我不太关心 "if"s。使用minBy会更优雅:
val least = seq.minBy(_.something)
... but minand minBythrow exceptions when the sequence is empty. Is there an idiomatic, more elegant way of finding the smallest element of a possibly empty list as an Option?
......但min与minBy抛出异常时序列为空。是否有一种惯用的、更优雅的方式来查找可能为空的列表中的最小元素作为Option?
采纳答案by Xavier Guihot
Starting Scala 2.13, minByOption/maxByOptionis now part of the standard library and returns Noneif the sequence is empty:
开始Scala 2.13, minByOption/maxByOption现在是标准库的一部分,None如果序列为空则返回:
seq.minByOption(_.something)
List((3, 'a'), (1, 'b'), (5, 'c')).minByOption(_._1) // Option[(Int, Char)] = Some((1,b))
List[(Int, Char)]().minByOption(_._1) // Option[(Int, Char)] = None
回答by Luigi Plinge
seq.reduceOption(_ min _)
does what you want?
你想要什么?
Edit: Here's an example incorporating your _.something:
编辑:这是一个包含您的示例_.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))
or, as generic method:
或者,作为通用方法:
def minOptionBy[A, B: Ordering](seq: Seq[A])(f: A => B) =
seq reduceOption Ordering.by(f).min
which you could invoke with minOptionBy(seq)(_.something)
你可以用它来调用 minOptionBy(seq)(_.something)
回答by Erik Kaplun
A safe, compact and O(n)version with Scalaz:
O(n)Scalaz 的安全、紧凑和版本:
xs.nonEmpty option xs.minBy(_.foo)
回答by Tomasz Nurkiewicz
Hardly an option for any larger list due to O(nlogn)complexity:
由于O(nlogn)复杂性,几乎没有选择任何更大的列表:
seq.sortBy(_.something).headOption
回答by Jean-Philippe Pellet
How about this?
这个怎么样?
import util.control.Exception._
allCatch opt seq.minBy(_.something)
Or, more verbose, if you don't want to swallow other exceptions:
或者,更详细地说,如果您不想吞下其他异常:
catching(classOf[UnsupportedOperationException]) opt seq.minBy(_.something)
Alternatively, you can pimp all collections with something like this:
或者,您可以使用以下内容对所有集合进行拉皮条:
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)
And then just write seq.minOptionBy(_.something).
然后只写seq.minOptionBy(_.something).
回答by user451151
You could always do something like:
你总是可以做这样的事情:
case class Foo(num: Int)
val foos: Seq[Foo] = Seq(Foo(1), Foo(2), Foo(3))
val noFoos: Seq[Foo] = Seq.empty
def minByOpt(foos: Seq[Foo]): Option[Foo] =
foos.foldLeft(None: Option[Foo]) { (acc, elem) =>
Option((elem +: acc.toSeq).minBy(_.num))
}
Then use like:
然后使用像:
scala> minByOpt(foos)
res0: Option[Foo] = Some(Foo(1))
scala> minByOpt(noFoos)
res1: Option[Foo] = None
回答by Tanvir Hassan
For scala < 2.13
对于 Scala < 2.13
Try(seq.minBy(_.something)).toOption
For scala 2.13
对于 Scala 2.13
seq.minByOption(_.something)
回答by Anar Amrastanov
Also, it is available to do like that
此外,它可以这样做
Some(seq).filter(_.nonEmpty).map(_.minBy(_.something))
回答by Dvir Arad
I have the same problem before, so I extends Ordered and implement the compare function. here is example:
我之前也遇到过同样的问题,所以我扩展了 Ordered 并实现了比较功能。这是示例:
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
}
}
so if I have a seq of Point I can ask for max or min method
所以如果我有一个点的序列,我可以要求最大或最小方法
var points = Seq[Point]()
val maxPoint = points.max
val minPoint = points.min

