Scala - 循环遍历列表时的状态

时间:2016-09-08 19:32:50

标签: scala functional-programming

新手问题。 我循环遍历列表,需要在项目之间保持状态。 例如

  val l = List("a", "1", "2", "3", "b", "4")
  var state: String = ""
  l.foreach(o => {
    if (toInt(o).isEmpty) state = o else println(state + o.toString)
  })

这里使用var的替代方法是什么?

5 个答案:

答案 0 :(得分:2)

你应该记住它有时(读取:当它使代码更易读和可由其他人维护时)可以在执行一些易于用可变状态表达的操作时使用可变性,只要该可变状态被限制为尽可能少的你的程序。使用(例如)foldLeft在不使用var的情况下维护累加器不会让您获得太多收益。

那就是说,这是一种方法:

val listOfThings: Seq[Either[Char, Int]] = Seq(Left('a'), Right(11), Right(212), Left('b'), Right(89))

val result = listOfThings.foldLeft(Seq[(Char, Seq[Int])]()) {
  case (accumulator, Left(nextChar)) => accumulator :+ (nextChar, Seq.empty)
  case (accumulator, Right(nextInt)) =>
    val (currentChar, currentSequence) = accumulator.last
    accumulator.dropRight(1) :+ (currentChar, currentSequence :+ nextInt)
}

result foreach {
  case (char, numbers) => println(numbers.map(num => s"$char-$num").mkString(" "))
}

答案 1 :(得分:2)

使用foldLeft

l.foldLeft(""){ (state, o) => 
  if(toInt(o).isEmpty) o 
  else {
    println(state + o.toString)
    state
  }
}

答案 2 :(得分:0)

传递arg:

scala> def collapse(header: String, vs: List[String]): Unit = vs match {
     | case Nil =>
     | case h :: t if h.forall(Character.isDigit) => println(s"$header$h") ; collapse(header, t)
     | case h :: t => collapse(h, t)
     | }
collapse: (header: String, vs: List[String])Unit

scala> collapse("", vs)
a1
a2
a3
b4

答案 3 :(得分:0)

在处理集合时,有两个主要选项可以在函数式编程中传递状态(我假设您希望将结果作为变量):

递归(经典)

val xs = List("a", "11", "212", "b", "89")

@annotation.tailrec
def fold(seq: ListBuffer[(String, ListBuffer[String])], 
         xs: Seq[String]): ListBuffer[(String, ListBuffer[String])] = {
  (seq, xs) match {
    case (_, Nil) =>
      seq
    case (_, c :: tail) if toInt(c).isEmpty  =>
      fold(seq :+ ((c, ListBuffer[String]())), tail)
    case (init :+ ((c, seq)), i :: tail) =>
      fold(init :+ ((c, seq :+ i)), tail)

  }
}

val result =
  fold(ListBuffer[(String, ListBuffer[String])](), xs)
  // Get rid of mutable ListBuffer
  .toSeq
  .map { 
    case (c, seq) => 
      (c, seq.toSeq)
  }
  //> List((a,List(11, 212)), (b,List(89)))

foldLeft

val xs = List("a", "11", "212", "b", "89")

val result = 
  xs.foldLeft(
    ListBuffer[(String, ListBuffer[String])]()
  ) {
    case (seq, c) if toInt(c).isEmpty  =>
      seq :+ ((c, ListBuffer[String]()))
    case (init :+ ((c, seq)), i) =>
      init :+ ((c, seq :+ i))
  }
  // Get rid of mutable ListBuffer
  .toSeq
  .map { 
    case (c, seq) => 
      (c, seq.toSeq)
  }
  //> List((a,List(11, 212)), (b,List(89)))

哪一个更好?除非你想在你的集合中间中止你的处理(例如在find中)foldLeft被认为是更好的方式,它的样板稍微少一些,但是它们非常相似。

我在这里使用ListBuffer来避免反转列表。

答案 4 :(得分:0)

简单如下:

val list: List[Int] = List.range(1, 10) // Create list

def updateState(i : Int) : Int = i + 1 // Generate new state, just add one to each position. That will be the state

list.foldRight[List[(Int,Int)]](List())((a, b) => (a, updateState(a)) :: b)

请注意,结果是Tuple2的列表:(元素,状态),每个状态取决于列表的元素。

希望这有帮助