scala 如何找到两个 Option[Int] 的 min() 或 max()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12639944/
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
How do I find the min() or max() of two Option[Int]
提问by Graham Lea
How would you find minValuebelow?
I have my own solution but want to see how others would do it.
你怎么找到minValue下面的?我有自己的解决方案,但想看看其他人会怎么做。
val i1: Option[Int] = ...
val i2: Option[Int] = ...
val defaultValue: Int = ...
val minValue = ?
采纳答案by Luigi Plinge
I think this is what you're after:
我认为这就是你所追求的:
val minValue = List(i1, i2).flatten match {
case Nil => defaultValue
case xs => xs.min
}
I'd avoid sortedsince sorting requires a lot more processing than simply finding the max or min (although it probably doesn't make much difference in this case).
我会避免,sorted因为排序比简单地找到最大值或最小值需要更多的处理(尽管在这种情况下它可能没有太大区别)。
回答by Travis Brown
Update: I just noticed that my solution below and the one in your answer behave differently—I read your question as asking for the minimum of the two values when there are two values, but in your answer you're effectively treating Noneas if it contained a value that's either bigger (for min) or smaller (for max) than anything else.
更新:我只是注意到我下面的解决方案和你的答案中的一个表现不同——我读你的问题是当有两个值时要求两个值中的最小值,但在你的答案中,你有效地将其None视为包含一个比其他任何东西都大 (for min) 或小 (for max) 的值。
To be more concrete: if i1is Some(1)and i2is None, my solution will return the default value, while yours will return 1.
更具体地说:如果i1isSome(1)和i2is None,我的解决方案将返回默认值,而你的将返回 1。
If you want the latter behavior, you can use the default semigroup instance for Option[A]and the tropical semigroupfor Int. In Scalaz 7, for example, you'd write:
如果你想后者的行为,你可以使用默认半群实例Option[A]和热带半群的Int。例如,在 Scalaz 7 中,你会这样写:
import scalaz._, Scalaz._
optionMonoid(Semigroup.minSemigroup[Int]).append(i1, i2) getOrElse defaultValue
Or the following shorthand:
或以下简写:
Tags.Min(i1) |+| Tags.Min(i2) getOrElse defaultValue
It's not as clean as the applicative functor solution below, but if that's your problem, that's your problem.
它不像下面的应用函子解决方案那么干净,但如果那是你的问题,那就是你的问题。
Here's a more idiomatic way that doesn't involve creating an extra list:
这是一种更惯用的方式,不涉及创建额外的列表:
(for { x <- i1; y <- i2 } yield math.min(x, y)) getOrElse defaultValue
Or, equivalently:
或者,等效地:
i1.flatMap(x => i2.map(math.min(x, _))) getOrElse defaultValue
What you're doing is "lifting" a two-place function (min) into an applicative functor (Option). Scalazmakes this easy with its applicative builder syntax:
你正在做的是将一个二位函数 ( min) “提升”到一个应用函子 ( Option) 中。Scalaz使用其适用的构建器语法使这变得容易:
import scalaz._, Scalaz._
(i1 |@| i2)(math.min) getOrElse defaultValue
The standard library solution isn't much less elegant in this case, but this is a useful abstraction to know about.
在这种情况下,标准库解决方案并没有那么优雅,但这是一个需要了解的有用抽象。
回答by Vladimir Kostyukov
I solved a similar problem using the following approach. We handle a special case when both of the options have values, otherwise we use an API method Option.orElse.
我使用以下方法解决了类似的问题。当两个选项都有值时,我们处理一种特殊情况,否则我们使用 API 方法Option.orElse。
val a: Option[Int] = Some(10)
val b: Option[Int] = Some(20)
val c: Option[Int] = (a, b) match {
case (Some(x), Some(y)) => Some(x min y)
case (x, y) => x orElse y
}
回答by Graham Lea
val minValue: Int = List(i1, i2).flatten.sorted.headOption getOrElse defaultValue
回答by Paul Cameron
You can use patterns in for expressions, values that do not match the pattern are discarded.
您可以在表达式中使用模式,与模式不匹配的值将被丢弃。
(for (Some(x) <- List(None, Some(3))) yield x) max
Not as good as the List.flatten approach though.
虽然不如 List.flatten 方法好。
回答by Yuval Itzchakov
Another option which wasn't mentioned is using reduceLeftOption(interchange math.maxand math.minas desired):
另一个没有提到的选项是使用reduceLeftOption(交换math.max和math.min根据需要):
val min = (first ++ second).reduceLeftOption(math.min).getOrElse(defaultValue)
scala> val first = Some(10)
first: Some[Int] = Some(10)
scala> val second: Option[Int] = None
second: Option[Int] = None
scala> val defaultMin = -1
defaultMin: Int = -1
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res7: Int = 10
scala> val first: Option[Int] = None
first: Option[Int] = None
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res8: Int = -1
scala> val first = Some(10)
first: Some[Int] = Some(10)
scala> val second = Some(42)
second: Some[Int] = Some(42)
scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res9: Int = 10
回答by Xavier Guihot
We can combine the 2 Options as an Iterablewith Option's ++operator, which allows us to use minOption(to nicely handle the case of the empty iterable formed by the None/Nonecase) and fallback on a default value if necessary with getOrElse:
我们可以将 2 Options组合为IterablewithOption的++运算符,这允许我们使用minOption(以很好地处None/None理由 case形成的空可迭代的情况)并在必要时回退默认值getOrElse:
(optionA ++ optionB).minOption.getOrElse(-1)
// None and None => -1
// Some(5) and None => 5
// None and Some(5) => 5
// Some(5) and Some(3) => 3
回答by 846846846
If you want to avoid using scalaz and map/for/getOrElse, you can do the following:
如果您想避免使用 scalaz 和 map/for/getOrElse,您可以执行以下操作:
val minValue = (i1, i2) match {
case (Some(x), Some(y)) => math.min(x, y)
case _ => defaultValue
}

