for ciclo array scala iteration

ciclo - Eficiente iteración con índice en Scala



ciclo for scala (12)

¿Qué tal esto?

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

Salida:

0: One 1: Two 2: Three

Como Scala no tiene el estilo antiguo de Java for bucles con índice,

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

¿Cómo podemos iterar de manera eficiente y sin usar var ''s?

Podrías hacer esto

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

pero la lista se cruza dos veces, no es muy eficiente.


Algunas formas más de iterar:

scala> xs.foreach (println) first second third

foreach, y similar, map, que devolvería algo (los resultados de la función, que es, para println, Unit, so a List of Units)

scala> val lens = for (x <- xs) yield (x.length) lens: Array[Int] = Array(5, 6, 5)

trabajar con los elementos, no con el índice

scala> ("" /: xs) (_ + _) res21: java.lang.String = firstsecondthird

plegable

for(int i=0, j=0; i+j<100; i+=j*2, j+=i+2) {...}

se puede hacer con recursión:

def ijIter (i: Int = 0, j: Int = 0, carry: Int = 0) : Int = if (i + j >= 100) carry else ijIter (i+2*j, j+i+2, carry / 3 + 2 * i - 4 * j + 10)

El carry-part es solo un ejemplo, para hacer algo con i y j. No necesita ser un Int.

para cosas más simples, más cerca de los bucles for:

scala> (1 until 4) res43: scala.collection.immutable.Range with scala.collection.immutable.Range.ByOne = Range(1, 2, 3) scala> (0 to 8 by 2) res44: scala.collection.immutable.Range = Range(0, 2, 4, 6, 8) scala> (26 to 13 by -3) res45: scala.collection.immutable.Range = Range(26, 23, 20, 17, 14)

o sin orden:

List (1, 3, 2, 5, 9, 7).foreach (print)


De hecho, al llamar a zipWithIndex en una colección lo atravesará y también creará una nueva colección para los pares. Para evitar esto, simplemente puede llamar a zipWithIndex en el iterador para la colección. Esto solo devolverá un nuevo iterador que realiza un seguimiento del índice mientras itera, por lo que no crea una colección adicional ni un recorrido adicional.

Así es como scala.collection.Iterator.zipWithIndex se implementa actualmente en 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 } }

Esto incluso debería ser un poco más eficiente que crear una vista en la colección.


En realidad, Scala tiene viejos bucles estilo Java con índice:

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

Donde 0 until xs.length o 0.until(xs.length) es un método de RichInt que devuelve el Range adecuado para el bucle.

Además, puedes probar el bucle con 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


Las soluciones propuestas adolecen del hecho de que iteran explícitamente sobre una colección o completan la colección en una función. Es más natural seguir con los modismos habituales de Scala y poner el índice dentro de los métodos habituales de mapa o foreach. Esto se puede hacer mediante la memorización. El código resultante podría verse como

myIterable map (doIndexed(someFunction))

Aquí hay una manera de lograr este propósito. Considere la siguiente utilidad:

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) } }

Esto ya es todo lo que necesitas Puede aplicar esto, por ejemplo, de la siguiente manera:

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

que resulta en la lista

List(97, 99, 101)

De esta manera, puede usar las funciones Traversables habituales a expensas de envolver su función efectiva. ¡Disfrutar!


Looping en scala es bastante simple. Crea cualquier matriz de tu elección por ej.

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

Tipos de bucles,

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


Mucho peor que atravesar dos veces, crea una matriz intermedia de pares. Puedes usar view . Cuando haces collection.view , puedes pensar en llamadas posteriores como actuando perezosamente, durante la iteración. Si desea recuperar una colección propia completa, llame a force al final. Aquí eso sería inútil y costoso. Así que cambie su código a

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


No hay nada en el archivo stdlib que lo haga por usted sin crear basura tupla, pero no es demasiado difícil escribir el suyo. Desafortunadamente, nunca me he molestado en averiguar cómo hacer el CanBuildFrom apropiado de raindance implícito para hacer que esas cosas sean genéricas en el tipo de colección a la que se aplican, pero si es posible, estoy seguro de que alguien nos iluminará. :)

def foreachWithIndex[A](as: Traversable[A])(f: (Int,A) => Unit) { var i = 0 for (a <- as) { f(i, a) i += 1 } } def mapWithIndex[A,B](in: List[A])(f: (Int,A) => B): List[B] = { def mapWithIndex0(in: List[A], gotSoFar: List[B], i: Int): List[B] = { in match { case Nil => gotSoFar.reverse case one :: more => mapWithIndex0(more, f(i, one) :: gotSoFar, i+1) } } mapWithIndex0(in, Nil, 0) } // Tests.... @Test def testForeachWithIndex() { var out = List[Int]() ScalaUtils.foreachWithIndex(List(1,2,3,4)) { (i, num) => out :+= i * num } assertEquals(List(0,2,6,12),out) } @Test def testMapWithIndex() { val out = ScalaUtils.mapWithIndex(List(4,3,2,1)) { (i, num) => i * num } assertEquals(List(0,3,4,3),out) }


Se ha mencionado que Scala tiene sintaxis for bucles for :

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

o simplemente

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

Sin embargo, también pediste eficiencia. Resulta que la sintaxis de Scala es en realidad azúcar sintáctica para métodos de orden superior como map , foreach , etc. Como tal, en algunos casos estos bucles pueden ser ineficientes, por ejemplo, ¿cómo optimizar las comprensiones y bucles en Scala?

(La buena noticia es que el equipo de Scala está trabajando para mejorar esto. Aquí está el problema en el rastreador de errores: https://issues.scala-lang.org/browse/SI-4633 )

Para obtener la máxima eficiencia, uno puede usar un ciclo while o, si insiste en eliminar usos de var , recursión final:

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"))

Tenga en cuenta que la anotación @tailrec opcional es útil para garantizar que el método sea realmente recursivo de cola. El compilador de Scala traduce las llamadas recursivas de cola en el código de bytes equivalente de los ciclos while.


Tengo los siguientes enfoques

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); } }


Una forma más:

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


Una forma simple y eficiente, inspirada en la implementación de transform en SeqLike.scala

var i = 0 xs foreach { el => println("String #" + i + " is " + xs(i)) i += 1 }