处理未初始化变量的惯用形式

时间:2012-04-04 15:04:29

标签: scala

我正在编写我的第一个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 _ =>
  }

我相信这是有效的,但我不确定这是否是最恰当的写作方式。这很清楚,但对于这样一个简单的“用例”来说有点冗长。

任何能够照亮我的功能性灯光的人?

感谢。

4 个答案:

答案 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