2

我正在编写我的第一个 Scala 脚本来感受这种语言,但对于实现某事的最佳方式,我有点困惑。

我的情况如下,我有一个需要调用 N 次的方法,这个方法在每次运行时返回一个 Int (可能不同,执行中有一个随机组件),我想保持最好的运行(这些运行返回的最小值)。

现在,来自 Java/Python 背景,我只需使用 null/None 初始化变量,然后在 if 中进行比较,例如:

best = None
for...
    result = executionOfThings()
    if(best is None or result < best):
        best = result

就是这样(请原谅半 python 伪代码)。

现在,在 Scala 上,我有点挣扎。我已经阅读了关于使用选项和模式匹配来实现相同效果的信息,我想我可以编写类似的代码(这是我能想到的最好的):

best match {
    case None => best = Some(res)
    case Some(x) if x > res => best = Some(res)
    case _ =>
  }

我相信这行得通,但我不确定这是否是最惯用的写法。这很清楚,但对于这样一个简单的“用例”来说有点冗长。

任何人都可以照亮我的功能?

谢谢。

4

4 回答 4

1

对于这个特殊问题,不是一般情况下,我建议使用初始化,Int.MaxValue只要你保证N >= 1. 那你就

if (result < best) best = result

您还可以best选择,

best = best.filter(_ >= result).orElse( Some(result) )

如果可选性很重要(例如,有可能N == 0,并且在这种情况下您没有通过代码采取不同的路径)。这是处理可能被替换的可选值的更通用方法:用于filter保留未替换的情况,并orElse在需要时填写替换。

于 2012-04-04T15:26:42.333 回答
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接受 B 和 PartialFunctionTuple2[B,A] => B并返回 B

两种方式是等价的。第一个可能更快,第二个更具可读性。两者都遍历列表,对每个值调用一个函数并返回最小值。你的片段中的哪一个是你想要的,对吧?

于 2012-04-04T16:18:12.750 回答
1

只需使用 min 函数:

(for (... executionOfThings()).min

例子:

((1 to 5).map (x => 4 * x * x - (x * x * x))).min
于 2012-04-04T17:01:29.797 回答
0

我想我会提供另一个惯用的解决方案。您可以使用Iterator.continually创建一个无限长的迭代器来延迟评估,take(N)将迭代器限制为 N 个元素,并使用它min来找到获胜者。

Iterator.continually { executionOfThings() }.take(N).min
于 2012-04-04T20:29:17.420 回答