【问题标题】:Replace all zeros in array with previous nonzero value with Scala使用 Scala 将数组中的所有零替换为先前的非零值
【发布时间】:2016-01-07 04:32:21
【问题描述】:

我想知道是否有一种巧妙的方法可以用 Scala 中的前一个非零值替换数组中的所有零。类似这个问题:pandas replace zeros with previous non zero value

对于滑动没有连续零的情况,我可以做到这一点:

scala> Array(1,2,3,0,5,6,7).sliding(2).map {case Array(v1, v2) => if (v2==0) v1 else v2}.toArray
res293: Array[Int] = Array(2, 3, 3, 5, 6, 7)

虽然我必须附加第一个值(在转换为数组之前我会这样做)。

如果有两个连续的零,上面的代码就不起作用:

scala> Array(1,2,3,0,0,6,7).sliding(2).map {case Array(v1, v2) => if (v2==0) v1 else v2}.toArray
res294: Array[Int] = Array(2, 3, 3, 0, 6, 7)

想要的结果是Array(2,3,3,3,6,7)

使用 for 循环很容易做到这一点;是否可以使用函数式方法?

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    使用scanLeft:

    Array(1,2,3,0,5,6,7).scanLeft(0)({(left, right) => if (right == 0) then left else right}).tail
    

    【讨论】:

    • 是的,这是“正确的方式” :) 我唯一要改变的是 { case(x, 0) => x; case (_, x) => x; } 而不是 if/else
    • 是的,这是我在学校学到的,我记得当时觉得它很简洁 :) 就我个人而言,在进行简单的数字比较时,我更喜欢 if/else,但这是一种风格偏好。跨度>
    【解决方案2】:

    可能有很多方法。您可以使用 foldLeft 来执行此操作,例如:

    Array(1,2,3,0,0,6,7)
        .foldLeft(List.empty[Int]){
            (acc, v) => if (v != 0) v :: acc else acc.head :: acc
        }.reverse.toArray
    

    【讨论】:

      【解决方案3】:

      递归方法,

      def f(xs: Array[Int], nonZ: Int): Array[Int] = {
        if (xs.isEmpty) xs
        else if (xs.head == 0) nonZ +: f(xs.tail, nonZ)
        else xs.head +: f(xs.tail, xs.head) 
      }
      

      可能会像这样调用val xs = Array(1,2,3,0,0,6,7)

      f(xs, xs.head)
      Array(1, 2, 3, 3, 3, 6, 7)
      

      请注意,问题不是针对以零开头的集合定义的。还要提到这个递归函数重复调用tailhead,这可能会减少到一个。

      【讨论】:

      • 感谢您的回答; Archeg 更符合我的要求,我将添加一些逻辑来处理以零开头的集合的情况。我从两个答案中都学到了。
      猜你喜欢
      • 2018-01-05
      • 2016-03-06
      • 2015-08-24
      • 2016-01-20
      • 2020-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多