【问题标题】:Scala reduce IDs from multiple tuples into one single IDScala 将多个元组中的 ID 减少为一个 ID
【发布时间】:2021-11-01 17:17:28
【问题描述】:

我有一个向量vecTest1,里面有如下的元组,每个元组有 6 个元素,第一个元素是一个键。我想通过一种算法来决定一个 BAB。

这就是我的做法

var strBAB:String="BAB1"
var intNumbBAB=vecTest1(0)._6

for (a<-1 to vecTest1.length-1){

intNumbBAB=intNumbBAB+vecTest1(a)._6
val douAAE = (vecTest1(a-1)._1 - vecTest1(a-1)._2) / vecTest1(a-1)._1
val douAAE1 = (vecTest1(a-1)._1 - vecTest1(a-1)._2 + vecTest1(a-1)._3) / vecTest1(a-1)._1
val douAAE2 = (vecTest1(a)._1 - vecTest1(a)._2 - vecTest1(a-1)._3) / vecTest1(a)._1

  if(douAAE1<=.04 && douAAE2>douAAE){
    if (vecTest1(a)._6>intNumbBAB) strBAB=vecTest1(a)._1
    else strBAB=vecTest1(a-1)._1
  }
}

有没有更好的方法来做到这一点?我是 Scala 的新手,但这似乎正在减少。那么有没有可能以一种更简洁的方式使用 reduce 呢?

【问题讨论】:

  • 看看zipWithIndexfoldLeft
  • 另外sliding(2) 可能会有所帮助
  • 我想知道如果你使用多维数组,你的代码会不会更干净。

标签: scala reduce


【解决方案1】:

您似乎想通过依次处理元素的序列来识别特定的元组。任何一种这样的循环都可以转换为某种形式的递归,这是 Scala 作为一种函数式编程语言的惯用方法。

这是一个编写为函数的版本,它返回所寻找的键值。

请注意,我使用类型 (BAB) 来更简洁地表示元组。我还概括了该方法,使其适用于任何Seq 值(VectorIndexedSeq 的一种类型,它是Seq 的一种类型);但在这种情况下,实际上不需要索引值。最后请注意,此实现中没有vars。

我不得不更改您的代码,因为不允许对字符串进行否定 (-) 和除法 (/) 操作,因此我已将对 _1String 值)的引用替换为 @ 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)

案例类以很少的开销添加了功能。

【讨论】:

  • 感谢您的意见。神秘的“数字”?用来决定最佳 BAB 的一切都来自这个 Vector。你的意思是我的代码中的 intNumbBAB?
猜你喜欢
  • 1970-01-01
  • 2017-09-11
  • 2018-08-03
  • 2017-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-28
相关资源
最近更新 更多