您似乎想通过依次处理元素的序列来识别特定的元组。任何一种这样的循环都可以转换为某种形式的递归,这是 Scala 作为一种函数式编程语言的惯用方法。
这是一个编写为函数的版本,它返回所寻找的键值。
请注意,我使用类型 (BAB) 来更简洁地表示元组。我还概括了该方法,使其适用于任何Seq 值(Vector 是IndexedSeq 的一种类型,它是Seq 的一种类型);但在这种情况下,实际上不需要索引值。最后请注意,此实现中没有vars。
我不得不更改您的代码,因为不允许对字符串进行否定 (-) 和除法 (/) 操作,因此我已将对 _1(String 值)的引用替换为 @ 987654331@(Double 值),将_2 替换为_3,并将_3 替换为_4。如果这不是您想要的,我深表歉意,但您的代码无法编译,而且我不知道代码中计算背后的目的。
import scala.annotation.tailrec
type BAB = (String, Double, Double, Double, Double, Int)
def findBAB(babs: Seq[BAB]): String = {
// Tail-recursive helper method to find the best BAB.
//
// "best" identifies the key of the best BAB found so far; "num" is
// whatever quantity intNumbBAB represents in your original code; "last"
// is the last BAB considered; and "rem" is the remainder of BAB's to be
// examined, which may be empty.
@tailrec
def find(best: String, num: Int, last: BAB, rem: Seq[BAB]): String = {
// If the remainder is empty, then return the best key. We're done.
if(rem.isEmpty) best
// Otherwise, perform another iteration.
else {
// Get head tuple of remainder, as the current BAB.
val cur = rem.head
// Calculations.
val newNum = num + cur._6
val douAAE = (last._2 - last._3) / last._2
val douAAE1 = (last._2 - last._3 + last._4) / last._2
val douAAE2 = (cur._2 - cur._3 - last._4) / cur._2
// Do we have a new best BAB key?
val newBest = if(douAAE1 <= 0.04 && douAAE2 > douAAE) {
if (cur._6 > newNum) cur._1
else last._1
}
else best
// Perform the next iteration.
find(newBest, newNum, cur, rem.tail)
}
}
// Start the ball rolling by initializing the search.
find(babs.head._1, babs.head._6, babs.head, babs.tail)
}
上面是一个相当手动的方法,它演示了递归,但可以说它并没有比你目前拥有的改进。
这是另一个使用foldLeft 高阶函数的版本,它更简洁但也可能更不直观:
type BAB = (String, Double, Double, Double, Double, Int)
def findBAB(babs: Seq[BAB]): String = {
// Perform a foldLeft on the tail of the sequence.
//
// The "zero" value is a tuple of the key of the first BAB, the "num"
// value, plus the first BAB itself
val result = babs.tail.foldLeft((babs.head._1, babs.head._6, babs.head)) {
// Break open the tuple arguments.
case ((best, num, last), cur) => {
// Calculations.
val newNum = num + cur._6
val douAAE = (last._2 - last._3) / last._2
val douAAE1 = (last._2 - last._3 + last._4) / last._2
val douAAE2 = (cur._2 - cur._3 - last._4) / cur._2
// Do we have a new best BAB key?
val newBest = if(douAAE1 <= 0.04 && douAAE2 > douAAE) {
if (cur._6 > newNum) cur._1
else last._1
}
else best
// Return a tuple with the values for the next iteration.
(newBest, newNum, cur)
}
}
// Return the first value of the tuple result (the BAB key).
result._1
}
reduce 操作是不可能的,因为需要的信息不仅仅是序列中的值(最佳 BAB 的键和神秘的“num”值)。
我还会考虑使用case class 代替元组,以便可以命名每个BAB 中的值,而不是通过数字引用。例如:
final case class BAB(key: String, v1: Double, v2: Double, v3: Double,
v4: Double, num: Int)
案例类以很少的开销添加了功能。