我正在编写我的第一个Scala脚本来感受这种语言,而且我对实现某些目标的最佳方式感到有些困惑。
我的情况如下,我有一个方法需要调用N次,这个方法在每次运行时返回一个Int(可能不同,执行时有一个随机组件),我想保持最好run(这些运行返回的最小值)。
现在,来自Java / Python背景,我只需使用null / None初始化变量,并在if中进行比较,例如:
best = None
for...
result = executionOfThings()
if(best is None or result < best):
best = result
就是这样(原谅半蟒蛇伪代码)。
现在,在Scala上,我有点挣扎。我已经阅读了Option和模式匹配的用法以达到同样的效果,我想我可以编写类似的东西(这是我能想到的最好的):
best match {
case None => best = Some(res)
case Some(x) if x > res => best = Some(res)
case _ =>
}
我相信这是有效的,但我不确定这是否是最恰当的写作方式。这很清楚,但对于这样一个简单的“用例”来说有点冗长。
任何能够照亮我的功能性灯光的人?
感谢。
答案 0 :(得分:1)
对于此特定的问题,一般情况下,只要您保证Int.MaxValue
,我建议您使用N >= 1
进行初始化。那你就是
if (result < best) best = result
您也可以best
作为选项,
best = best.filter(_ >= result).orElse( Some(result) )
如果选项很重要(例如,N == 0
可能是filter
,并且在这种情况下您没有通过代码采用不同的路径)。这是处理可能被替换的可选值的更通用方法:使用orElse
来保留未替换的案例,并{{1}}在需要时填写替换值。
答案 1 :(得分:1)
编辑:调整为@ user-unknown的建议
我建议你重新考虑整个计算更具功能性。你改变了应该避免的状态。我可以想到你的代码的递归版本:
def calcBest[A](xs: List[A])(f: A => Int): Int = {
def calcBest(xs: List[A], best: Int = Int.MaxValue): Int = xs match {
// will match an empty list
case Nil => best
// x will hold the head of the list and rest the rest ;-)
case x :: rest => calcBest(rest, math.min(f(x), best))
}
calcBest(xs)
}
可以使用calcBest(List(7,5,3,8,2))(_*2) // => res0: Int = 4
有了这个,你根本没有可变的状态。
另一种方法是在列表中使用foldLeft:
list.foldLeft(Int.MaxValue) { case (best,x) => math.min(calculation(x),best) }
foldLeft
获取Tuple2[B,A] => B
的B和PartialFunction并返回B
两种方式都是等价的。第一个可能更快,第二个更可读。两个遍历列表调用每个值的函数并返回最小值。哪个来自你的代码片段就是你想要的,对吗?
答案 2 :(得分:1)
只需使用min函数:
(for (... executionOfThings()).min
示例:
((1 to 5).map (x => 4 * x * x - (x * x * x))).min
答案 3 :(得分:0)
我以为我会提供另一个惯用的解决方案。您可以使用Iterator.continually
创建一个懒惰评估的无限长度迭代器,take(N)
将迭代器限制为N个元素,并使用min
查找获胜者。
Iterator.continually { executionOfThings() }.take(N).min