Эффективная итерация с индексом в Scala - PullRequest
75 голосов
/ 26 июля 2011

Поскольку в Scala отсутствует старый цикл Java for с индексом,

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

Как мы можем выполнять итерацию эффективно, без использования var?

Вы можетесделайте это

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

, но список просматривается дважды - не очень эффективно.

Ответы [ 12 ]

2 голосов
/ 20 декабря 2011

Простой и эффективный способ, вдохновленный реализацией transform в SeqLike.scala

    var i = 0
    xs foreach { el =>
      println("String #" + i + " is " + xs(i))
      i += 1
    }
0 голосов
/ 08 мая 2012

Предлагаемые решения страдают от того факта, что они либо явно перебирают коллекцию, либо заполняют коллекцию функцией. Более естественно придерживаться обычных идиом Scala и помещать указатель в обычные методы map или foreach. Это можно сделать с помощью запоминания. Полученный код может выглядеть как

myIterable map (doIndexed(someFunction))

Вот способ достижения этой цели. Рассмотрим следующую утилиту:

object TraversableUtil {
    class IndexMemoizingFunction[A, B](f: (Int, A) => B) extends Function1[A, B] {
        private var index = 0
        override def apply(a: A): B = {
            val ret = f(index, a)
            index += 1
            ret
        }
    }

    def doIndexed[A, B](f: (Int, A) => B): A => B = {
        new IndexMemoizingFunction(f)
    }
}

Это уже все, что тебе нужно. Вы можете применить это, например, следующим образом:

import TraversableUtil._
List('a','b','c').map(doIndexed((i, char) => char + i))

, что приводит к списку

List(97, 99, 101)

Таким образом, вы можете использовать обычные функции Traversable за счет обертывания вашей эффективной функции. Наслаждайтесь!

...