将以下代码转换为功能范例

时间:2018-04-19 17:48:48

标签: scala

我有一件工作正常的作品。我只是想把它转换成功能风格。问题是我将编写的集合函数用于将集合转换为值。这是用于火花流的UpdateStateByKey函数的更新方法的签名。

def updateFunction(newValues: Seq[(Int)], runningCount: Option[(Int)]): Option[(Int)] = 
{
   var result: Option[(Int)] = null

   if(newValues.isEmpty){ 
         result=Some(runningCount.get)
      }
   else
   {
        newValues.foreach 
      { x => 
        {
             if(runningCount.isEmpty){
             result=Some(x)
        }
         else
        {
              result=Some(x+runningCount.get) 
        }
        } 
      }
   }
  result
}

将由此

调用
val reducedRDD=keyValuelines.reduceByKey((x,y)=>(x+y))
val updatedRdd= reducedRDD.updateStateByKey(updateFunction)

如此有效

如果newValues为空,请获取runningCount。否则:

  1. 如果runningCount为空 - 求和newValues
  2. 如果存在运行计数 - 将newValues和输出与运行计数相加
  3. 我不想使用foreach,因为它什么都不返回。所有其他收集功能似乎都不符合此标准。

    我尝试将此代码转换为功能代码。有人可以确认这是正确的吗?

    def updateFunctionVal(newValues: Seq[(Int)], runningCount: Option[(Int)]): Option[(Int)] = {
    
        val result = if (newValues.isEmpty) { //check if the key is present in new batch if not then return the old values
          Some(runningCount.get)
        }
        else {
          runningCount match {
            case x if runningCount.isEmpty => Some(newValues.fold(0)(_ + _))
            case _ => Some(newValues.fold(0)(_ + _) + runningCount.get)
          }
        }
        result
      }
    

3 个答案:

答案 0 :(得分:2)

鉴于帖子中隐藏的描述,这是使用reduceOption的一个实现:

/*
If the newValues is empty, get the runningCount. Else:
  If running count is present - sum the newValues and add runningCount
  else - sum the newValues
 */
def updateFunction(newValues: Seq[(Int)], runningCount: Option[(Int)]): Option[Int] = {
  newValues
    .reduceOption(_ + _)                // sum of values, or None
    .map(_ + runningCount.getOrElse(0)) // add runningCount or 0 to sum
    .orElse(runningCount)               // if newValues was empty, just return runningCount
}

println(updateFunction(Seq(), Some(3)))     // Some(3)
println(updateFunction(Seq(4, 5), Some(3))) // Some(12)
println(updateFunction(Seq(4, 5), None))    // Some(9)
println(updateFunction(Seq(), None))        // None

答案 1 :(得分:1)

所以只是为了清楚函数的预期输出:如果newValues为空,只需返回runningCount。如果它不为空,则返回最后一个值,无论添加到runningCount中的任何内容(如果存在)。那是对的吗?如果newValues为空且runningCountNone,该怎么办?现在你抛出异常。这是一个在这种情况下返回None的版本:

def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = {
  newValues.lastOption match {
    case None => runningCount
    case Some(x) => Some(x + runningCount.getOrElse(0))
  }
}

或基本相同,但更紧凑:

def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = {
  newValues.lastOption.map(_ + runningCount.getOrElse(0)).orElse(runningCount)
}

编辑:您的第二次尝试具有完全不同的逻辑和输出。如果你用简单的英语澄清你希望函数做什么会有所帮助。

答案 2 :(得分:1)

假设我理解你试图实施的逻辑:

您有一个运行计数,以及一个应该全部添加到计数中的值列表。我相信您正在寻找的是foldLeft/Right操作:

def update(newValues: Seq[(Int)], runningCount: Option[(Int)]) =
    newValues.foldLeft[Option[(Int)]](runningCount)((count, value) =>
        count match {
            case Some(initial) => Some(initial + value)
            case None => Some(value)
        })

请注意,常规fold不会在这里工作,因为它只针对扩展Int的类型定义(我认为这与关联规则有关) ,因为fold没有定义它是从左还是右进行折叠