scala-foldLeft用序列号填充连续的零间隙

时间:2018-11-16 12:38:25

标签: scala functional-programming

我在foldLeft中有一个特殊的情况

scala> val nums = List(1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1)
nums: List[Int] = List(1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1)

我需要通过以2,3,4的序列号填充连续的零来获取输出

必需的输出:

List(1, 1, 2, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5, 1, 1) 

我实际上需要将此应用于列表[(String,Int)]

来自

List(("a",1),("b",1),("b",0),("a",1),("a",0),("a",0),("d",1),("d",0),("d",0),("c",1),("c",0), ("c",0), ("c",0), ("c",0), ("d",1), ("a",1))

到必需的输出

List(("a",1),("b",1),("b",2),("a",1),("a",2),("a",3),("d",1),("d",2),("d",3),("c",1),("c",2), ("c",3), ("c",4), ("c",5), ("d",1), ("a",1))

我正在尝试在List [Int]上进行以下操作,但出现错误

scala> nums.foldLeft(List[Int]())( (m:List[Int],n:Int) => { val p = if(n==0) m.last+1 else n; m.++ List(p) })
<console>:26: error: missing argument list for method ++ in class List
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `$plus$plus _` or `$plus$plus(_)(_)` instead of `$plus$plus`.
       nums.foldLeft(List[Int]())( (m:List[Int],n:Int) => { val p = if(n==0) m.last+1 else n; m.++ List(p) })
                                                                                                ^

scala>

如何解决此问题并将逻辑应用于List [(String,Int])?。

3 个答案:

答案 0 :(得分:3)

m.++ List(p)是无效的Scala语法。应该是m ++ List(p)

但是您也可以只使用运算符:+

示例(仅包括Int(String, Int)):

val stringsAndNums = List(
  ("a",1),("b",1),("b",0),("a",1),("a",0),("a",0),("d",1),("d",0),("d",0),("c",1),("c",0), ("c",0), ("c",0), ("c",0), ("d",1), ("a",1)
)

// Without strings

val nums = stringsAndNums.map{case (a: String, b: Int) => b} 

println(
  nums.foldLeft(
    List[Int]()
  )(
    (m: List[Int], n: Int) => {

      val p = if(n == 0) m.last + 1 else n

      m :+ p
    }
  )
)

// With strings

println(
  stringsAndNums.foldLeft(
    List[(String, Int)]()
  )(
    (m: List[(String, Int)], n: (String, Int)) => {

      val p = if(n._2 == 0) (n._1, m.last._2 + 1) else n

      m :+ p
    }
  )
)

结果:

List(1, 1, 2, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5, 1, 1)
List((a,1), (b,1), (b,2), (a,1), (a,2), (a,3), (d,1), (d,2), (d,3), (c,1), (c,2), (c,3), (c,4), (c,5), (d,1), (a,1))

Try it out!

答案 1 :(得分:3)

实际上,方法scanLeftfoldLeft更适合该问题。 在这里:

对于List[Int]

scala> val nums = List(1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1)
nums: List[Int] = List(1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1)

scala> nums.scanLeft(0){ (r, n) => if(n == 0) r + 1 else n }.tail
res1: List[Int] = List(1, 1, 2, 1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5, 1, 1)

对于List[(String Int)]

scala> val xs = List(("a",1),("b",1),("b",0),("a",1),("a",0),("a",0),("d",1),("d",0),("d",0),("c",1),("c",0), ("c",0), ("c",0), ("c",0), ("d",1), ("a",1))
xs: List[(String, Int)] = List((a,1), (b,1), (b,0), (a,1), (a,0), (a,0), (d,1), (d,0), (d,0), (c,1), (c,0), (c,0), (c,0), (c,0), (d,1), (a,1))

scala> xs.scanLeft(("", 0)){ case((_, r), (c, n)) => (c, if(n == 0) r+1 else n) }.tail
res2: List[(String, Int)] = List((a,1), (b,1), (b,2), (a,1), (a,2), (a,3), (d,1), (d,2), (d,3), (c,1), (c,2), (c,3), (c,4), (c,5), (d,1), (a,1))

即使第一个数字为零,此解决方案也可以使用,@ Markus Appel的解决方案在这种情况下不起作用。

答案 2 :(得分:2)

请注意,由于嵌套调用slow(列表中的O(n^2)),.last版本为O(n)

def slow(list: List[(String, Int)]): List[(String, Int)] =
  list.foldLeft(List[(String, Int)]()) {
    (m: List[(String, Int)], n: (String, Int)) => {
      val p = if (n._2 == 0) (n._1, m.last._2 + 1) else n
      m :+ p
    }
  }

您可以通过将列表附加到头部并在最后将其反转来构建O(n)解决方案:

def fast(list: List[(String, Int)]): List[(String, Int)] =
  list.foldLeft(List[(String, Int)]()) {
    (m: List[(String, Int)], n: (String, Int)) => {
      val p = if (n._2 == 0) (n._1, m.head._2 + 1) else n
      p +: m
    }
  }.reverse

在我的计算机上,对于32000大小的列表,快速变体需要18毫秒,而慢速变体需要6秒。