[scala] 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))
}

사용하지 않고 어떻게 효율적으로 반복 할 수 있습니까? var‘s 있습니까?

당신은 이것을 할 수 있습니다

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

그러나 목록은 두 번 순회됩니다-그리 효율적이지 않습니다.



답변

두 번 순회하는 것보다 훨씬 더 나쁜 것은 쌍의 중간 배열을 생성한다는 것입니다. 사용할 수 있습니다 view. 을 수행하면 collection.view후속 호출이 반복 중에 느리게 작동한다고 생각할 수 있습니다. 완전히 실현 된 적절한 컬렉션을 되 찾으 force려면 마지막에 전화 하십시오. 여기에서는 쓸모없고 비용이 많이 듭니다. 따라서 코드를

for((x,i) <- xs.view.zipWithIndex) println("String #" + i + " is " + x)


답변

Scala 에는for 루프 구문 이 있다고 언급되었습니다 .

for (i <- 0 until xs.length) ...

또는 간단히

for (i <- xs.indices) ...

그러나 효율성도 요구했습니다. 그것은 스칼라 밝혀 for구문은 실제로 같은 고차 방법에 대한 문법 설탕이다 map, foreach등 등과 같은, 어떤 경우에는 이러한 루프가 비효율적 일 수있다, 예를 들어 어떻게 최적화에 스칼라 및 루프 – 지능형 하시나요?

(좋은 소식은 Scala 팀이이 문제를 개선하기 위해 노력하고 있다는 것입니다. 다음은 버그 추적기의 문제입니다. 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"))

점을 유의 옵션 @tailrec 주석이 방법은 실제로 꼬리 재귀 있음을 보장하는 데 유용합니다. Scala 컴파일러는 tail-recursive 호출을 while 루프에 해당하는 바이트 코드로 변환합니다.


답변

한 가지 더 방법 :

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


답변

실제로 스칼라에는 인덱스가있는 오래된 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

어디 0 until xs.length또는 0.until(xs.length)A는 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


답변

이건 어때?

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

산출:

0: One
1: Two
2: Three


답변

스칼라에서 반복하는 것은 매우 간단합니다. 예를 들어 원하는 배열을 만듭니다.

val myArray = new Array[String](3)
myArray(0)="0";
myArray(1)="1";
myArray(2)="2";

루프 유형,

for(data <- myArray)println(data)

for (i <- 0 until myArray.size)
println(i + ": " + myArray(i))


답변

실제로 zipWithIndex컬렉션을 호출 하면 컬렉션을 순회하고 쌍에 대한 새 컬렉션도 생성됩니다. 이를 방지하려면 zipWithIndex컬렉션의 반복기를 호출 하면됩니다. 이것은 반복하는 동안 인덱스를 추적하는 새 반복자를 반환하므로 추가 컬렉션이나 추가 순회를 만들지 않습니다.

scala.collection.Iterator.zipWithIndex현재 2.10.3에서 구현되는 방법 은 다음과 같습니다.

  def zipWithIndex: Iterator[(A, Int)] = new AbstractIterator[(A, Int)] {
    var idx = 0
    def hasNext = self.hasNext
    def next = {
      val ret = (self.next, idx)
      idx += 1
      ret
    }
  }

이것은 컬렉션에 대한 뷰를 만드는 것보다 조금 더 효율적이어야합니다.