使用Scala中的索引进行高效迭代

sna*_*ppy 77 iteration scala

由于Scala没有for带索引的旧Java样式循环,

// does not work
val xs = Array("first", "second", "third")
for (i=0; i<xs.length; i++) {
  println("String #" + i + " is " + xs(i))
}
Run Code Online (Sandbox Code Playgroud)

我们如何有效地迭代,而不使用var

你可以做到这一点

val xs = Array("first", "second", "third")
val indexed = xs zipWithIndex
for (x <- indexed) println("String #" + x._2 + " is " + x._1)
Run Code Online (Sandbox Code Playgroud)

但列表遍历了两次 - 效率不高.

Did*_*ont 121

比遍历两次更糟糕的是,它创建了一对中间数组.你可以用view.当你这样做时collection.view,你可以认为后续调用在迭代期间是懒惰的.如果你想找回一个完全实现的完整系列,你可以force在最后打电话.这将是无用的和昂贵的.所以将代码更改为

for((x,i) <- xs.view.zipWithIndex) println("String #" + i + " is " + x)
Run Code Online (Sandbox Code Playgroud)

  • 不错的想法,只有一次遍历,但它也创建了n对,即使它没有创建适当的新集合. (6认同)
  • 完全正确.好吧,可能有一种模糊的希望,JVM可能会优化这些创作,但我不会指望它.我没有看到一个不会基于索引迭代的解决方案. (2认同)
  • 不会使用xs.iterator.zipWithIndex一样好吗? (2认同)

Kip*_*ros 66

有人提到Scala 确实for循环语法:

for (i <- 0 until xs.length) ...
Run Code Online (Sandbox Code Playgroud)

或者干脆

for (i <- xs.indices) ...
Run Code Online (Sandbox Code Playgroud)

但是,你也要求提高效率.事实证明,Scala的for语法实际上是更高阶的方法,如语法糖map,foreach等.因此,在某些情况下,这些循环可以是低效的,例如如何优化,内涵和循环在Scala呢?

(好消息是Scala团队正在努力改进这一点.这是bug跟踪器中的问题:https://issues.scala-lang.org/browse/SI-4633)

为了获得最高效率,可以使用while循环,或者,如果您坚持删除var尾递归的用法:

import scala.annotation.tailrec

@tailrec def printArray(i: Int, xs: Array[String]) {
  if (i < xs.length) {
    println("String #" + i + " is " + xs(i))
    printArray(i+1, xs)
  }
}
printArray(0, Array("first", "second", "third"))
Run Code Online (Sandbox Code Playgroud)

请注意,可选 @tailrec注释对于确保方法实际上是尾递归非常有用.Scala编译器将尾递归调用转换为等效于while循环的字节代码.


mis*_*tor 18

还有一种方法:

scala> val xs = Array("first", "second", "third")
xs: Array[java.lang.String] = Array(first, second, third)

scala> for (i <- xs.indices)
     |   println(i + ": " + xs(i))
0: first
1: second
2: third
Run Code Online (Sandbox Code Playgroud)

  • 我真的很喜欢你指出索引方法/功能.它降低了复杂性,几乎消除了一整套"一个接一个"的错误,这是所有软件工程中最常见的编程错误/错误. (5认同)

om-*_*nom 13

实际上,scala具有索引的旧Java样式循环:

scala> val xs = Array("first","second","third")
xs: Array[java.lang.String] = Array(first, second, third)

scala> for (i <- 0 until xs.length)
     | println("String # " + i + " is "+ xs(i))

String # 0 is first
String # 1 is second
String # 2 is third
Run Code Online (Sandbox Code Playgroud)

其中0 until xs.length或者0.until(xs.length)是一个RichInt返回方法Range适于循环.

此外,您可以尝试循环to:

scala> for (i <- 0 to xs.length-1)
     | println("String # " + i + " is "+ xs(i))
String # 0 is first
String # 1 is second
String # 2 is third
Run Code Online (Sandbox Code Playgroud)

  • 列表上的`xs(i)`将复杂度提高到O(n ^ 2) (5认同)
  • @dhfromkorea是的,对于数组应该很快(实际上是O(n)) (2认同)

Mat*_*ltz 6

这个怎么样?

val a = Array("One", "Two", "Three")
a.foldLeft(0) ((i, x) => {println(i + ": " + x); i + 1;} )
Run Code Online (Sandbox Code Playgroud)

输出:

0: One
1: Two
2: Three
Run Code Online (Sandbox Code Playgroud)


Pra*_*yat 5

scala 中的循环非常简单。创建您选择的任何数组。

val myArray = new Array[String](3)
myArray(0)="0";
myArray(1)="1";
myArray(2)="2";
Run Code Online (Sandbox Code Playgroud)

循环类型,

for(data <- myArray)println(data)

for (i <- 0 until myArray.size)
println(i + ": " + myArray(i))
Run Code Online (Sandbox Code Playgroud)


ani*_*ish 5

我有以下方法

object HelloV2 {

   def main(args: Array[String]) {

     //Efficient iteration with index in Scala

     //Approach #1
     var msg = "";

     for (i <- args.indices)
     {
       msg+=(args(i));
     }
     var msg1="";

     //Approach #2
     for (i <- 0 until args.length) 
     {
       msg1 += (args(i));
     }

     //Approach #3
     var msg3=""
     args.foreach{
       arg =>
        msg3 += (arg)
     }


      println("msg= " + msg);

      println("msg1= " + msg1);

      println("msg3= " + msg3);

   }
}
Run Code Online (Sandbox Code Playgroud)