Scala - peut donner un rendement utilisé plusieurs fois avec une boucle?
-
16-09-2019 - |
Question
Un exemple:
val l = List(1,2,3)
val t = List(-1,-2,-3)
Puis-je faire quelque chose comme ça?
for (i <- 0 to 10) yield (l(i)) yield (t(i))
En fait, je veux obtenir plusieurs résultats pour chaque itération.
La solution
Il est pas clair ce que vous demandez - ce que vous attendez la sémantique de multiples rendement à. Une chose, cependant, est que vous voulez sans doute de ne jamais utiliser des index pour naviguer dans une liste -. Chaque appel à t (i) est O (i) d'exécuter
Alors, voici une possibilité que vous pourriez demander pour
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))
Et voici une autre possibilité que vous pourriez demander pour
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))
Le dernier est juste du sucre syntaxique pour
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))
Une troisième possibilité est que vous voulez les entrelacer
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)
C'est le sucre syntaxe
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)
Autres conseils
Non, vous ne pouvez pas utiliser plusieurs clauses de rendement, mais il y a des contournements. Par exemple:
for (i <- 0 to 10;
r <- List(l(i), t(i)))
yield r
Vous pouvez imbriquer pour-compréhensions, bien sûr, mais cela entraînerait une liste de listes d'éléments, que je ne crois pas est ce que vous voulez.
Les rendements peuvent être imbriquées, ce qui aurait pour effet ...
for (i <- 0 to 3) yield {
for (j <- 0 to 2) yield (i,j)
}
dans un vecteur de vecteur:
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 solution est aplaties sémantiquement différent.
Voici une solution de type agnostique pour un nombre inconnu, différents d'éléments dans un nombre inconnu de listes:
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
}
Pour 2 listes, il est overengineered. Vous pouvez bien appeler
xproduct (List (l, t))
Il semble que non. Je reçois une erreur de compilation quand je l'essaye.
On dirait que pour .. le rendement est une expression. Vous ne pouvez pas avoir deux rendements, puisque ce n'est pas vraiment partie de l'expression.
Si vous souhaitez obtenir des valeurs multiples, pourquoi ne pas les céder comme tuple ou une liste?
Par exemple:
for( t <- List(1,2,3); l <- List(-1,-2,-3))
yield (t, l)
Peut-être rendement est pas la meilleure façon d'aller? Peut-être appending simple tableau pourrait être utilisé ici.