Scala计数内循环的迭代次数

Deb*_*ski 1 iterator functional-programming scala count immutability

如果我想枚举Scala中内循环的迭代,我将如何以函数式方式处理它?

例如,我将如何重写以下代码:

val documents = List("a" :: "b" :: Nil, "aa" :: "bb" :: Nil, "aaa" :: Nil)
var currentPageNumber = 0

documents.foreach { doc =>
  for (page <- doc) {
    currentPageNumber += 1
    println("%d: %s".format(currentPageNumber.head, page)
    // do something with page
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以摆脱var使用val currentPageNumber = Iterator.from(0)但这仍然意味着我实际上需要在循环之外声明它.

有没有一个技巧不会暴露currentPageNumber到外部范围 - 就像zipWithIndex计数器一样 - 只存在于循环内部?

编辑:

我也发现了一个版本,scanLeft但我觉得它很混乱.但也许有人可以以某种方式优化它.

documents.scanLeft(0) { case (cnt, doc) =>
  doc.zip(Iterator.from(cnt + 1).toIterable).map { case(page, cnt) =>
    println("%d: %s".format(cnt, page))
    cnt
  } last
}
Run Code Online (Sandbox Code Playgroud)

自己的解决方案(现在):

谢谢大家,我想我的想法是这样的

documents.flatMap{ doc =>
  for (page <- doc) yield {
    currentPageNumber: Int =>
      "%d: %s".format(currentPageNumber, page)
}}.zipWithIndex.map (t => t._1(t._2 + 1)) map(println)
Run Code Online (Sandbox Code Playgroud)

所以,诀窍是currentPageNumber不确定,直到可以实际应用zipWithIndex.

Ken*_*oom 6

我认为你使用的命令式版本可能更好,因为printf无论如何都有副作用,但如果你想要一些功能,你可以这样做:

documents.foldLeft(1){ (docStartingPage,doc) =>
   doc.foldLeft(docStartingPage){ (currentPageNumber, page) =>
      printf("%d: %s\n", currentPageNumber, page)
      currentPageNumber + 1
   }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果外部循环中的数字将再次出现在内部循环中,则该数字必须可用.

您也可以尝试以下操作,但是您将丢失有关文档开始和结束位置的任何信息.

for ( (page,pageNumber) <- documents.flatten.zipWithIndex )
  printf("%d: %s\n", pageNumber + 1, page)
Run Code Online (Sandbox Code Playgroud)