Scala 将多个元组中的 ID 减少为一个 ID

Posted

技术标签:

【中文标题】Scala 将多个元组中的 ID 减少为一个 ID【英文标题】:Scala reduce IDs from multiple tuples into one single 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) 可能会有所帮助 我想知道如果你使用多维数组,你的代码会不会更干净。 【参考方案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?

以上是关于Scala 将多个元组中的 ID 减少为一个 ID的主要内容,如果未能解决你的问题,请参考以下文章

从元组中的字典创建数据框

将键值元组包转换为 Apache Pig 中的映射

Python列表元组字典集合的内置使用方法

Scala Spark 地图类型匹配问题

我可以按类型访问什么类型的集合,并在必要时找不到

将结果减少到累积的组中