Scala - puede rendir usarse múltiples veces con un bucle for?
-
16-09-2019 - |
Pregunta
Un ejemplo:
val l = List(1,2,3)
val t = List(-1,-2,-3)
¿Puedo hacer algo como esto?
for (i <- 0 to 10) yield (l(i)) yield (t(i))
Básicamente quiero dar varios resultados para cada iteración.
Solución
No está claro lo que está pidiendo - lo que espera la semántica de rendimiento múltiple que se desea. Una cosa, sin embargo, es que probablemente nunca quiere utilizar índices para navegar por una lista -. Cada llamada a T (i) es O (i) para ejecutar
Así que aquí hay una posibilidad de que se puede preguntar por
scala> val l = List(1,2,3); val t = List(-1,-2,-3)
l: List[Int] = List(1, 2, 3)
t: List[Int] = List(-1, -2, -3)
scala> val pairs = l zip t
pairs: List[(Int, Int)] = List((1,-1), (2,-2), (3,-3))
Y aquí hay otra posibilidad que se puede preguntar por
scala> val crossProduct = for (x <- l; y <- t) yield (x,y)
crossProduct: List[(Int, Int)] = List((1,-1), (1,-2), (1,-3), (2,-1), (2,-2), (2,-3), (3,-1), (3,-2), (3,-3))
La última es simplemente azúcar sintáctica para
scala> val crossProduct2 = l flatMap {x => t map {y => (x,y)}}
crossProduct2: List[(Int, Int)] = List((1,-1), (1,-2), (1,-3), (2,-1), (2,-2), (2,-3), (3,-1), (3,-2), (3,-3))
Una tercera posibilidad es que desea intercalar ellos
scala> val interleaved = for ((x,y) <- l zip t; r <- List(x,y)) yield r
interleaved: List[Int] = List(1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10)
Eso es azúcar sintaxis de
scala> val interleaved2 = l zip t flatMap {case (x,y) => List(x,y)}
interleaved2: List[Int] = List(1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10)
Otros consejos
No, no se puede utilizar varias cláusulas de rendimiento, pero hay soluciones temporales. Por ejemplo:
for (i <- 0 to 10;
r <- List(l(i), t(i)))
yield r
Puede anidar para-comprensiones, por supuesto, pero eso daría lugar a una lista de listas de elementos, que no creo que es lo que desea.
Los rendimientos se pueden anidar, lo que daría lugar ...
for (i <- 0 to 3) yield {
for (j <- 0 to 2) yield (i,j)
}
en un vector de vector:
scala.collection.immutable.IndexedSeq[scala.collection.immutable.IndexedSeq[(Int, Int)]]
= Vector(Vector((0,0), (0,1), (0,2)), Vector((1,0), (1,1), (1,2)), Vector((2,0), (2,1), (2,2)), Vector((3,0), (3,1), (3,2)))
for (i <- 0 to 3;
j <- 0 to 2) yield (i,j)
La solución aplanada es semánticamente diferente.
Aquí es una solución de tipo agnóstico para un número variable desconocida, de elementos en un número desconocido de listas:
def xproduct (xx: List [List[_]]) : List [List[_]] =
xx match {
case aa :: bb :: Nil =>
aa.map (a => bb.map (b => List (a, b))).flatten
case aa :: bb :: cc =>
xproduct (bb :: cc).map (li => aa.map (a => a :: li)).flatten
case _ => xx
}
Para 2 Listas es overengineered. Aunque se podía llamarlo
xproduct (List (l, t))
Al parecer no. Me sale un error de compilación cuando lo intento.
Parece que para .. rendimiento es una expresión. No se puede tener dos rendimientos, ya que eso no es realmente parte de la expresión.
Si desea obtener varios valores, por qué no cederlos como una tupla o una lista?
Por ejemplo:
for( t <- List(1,2,3); l <- List(-1,-2,-3))
yield (t, l)
Tal vez rendimiento no es el mejor camino a seguir? Tal vez sencilla anexar matriz podría ser utilizado aquí.