Je veux mettre en place un itérateur paresseux qui donne l'élément suivant dans chaque appel, dans une boucle imbriquée à 3 niveaux.
Y a-t-il quelque chose de similaire dans Scala à cet extrait de C #: P>
foreach (int i in ...) { foreach (int j in ...) { foreach (int k in ...) { yield return do(i,j,k); } } }
8 Réponses :
Les types de séquence Scala ont tous une méthode .View qui produit un équivalent paresseux de la collection. Vous pouvez jouer avec ce qui suit dans la réponse à repl (après émettant : silencieux code> pour l'empêcher de forcer la collection pour imprimer les résultats de la commande):
def log[A](a: A) = { println(a); a }
for (i <- 1 to 10) yield log(i)
for (i <- (1 to 10) view) yield log(i)
Il suffit de lire les 20 premiers liens connexes qui sont montrent sur le côté (et, en effet, où vous avez montré lorsque vous avez écrit le titre de votre question). P>
J'ai bien lu les liens à fond - aucun d'entre eux n'a montré exactement ce que je cherchais, et il semble que cela n'existe pas du tout ... C # 's Le rendement est plus puissant (au moins pour ce dont j'ai besoin). De plus, j'ai pensé qu'il était possible que cette fonctionnalité soit ajoutée à Scala après la demande de ces questions précédentes.
@Duduamar de côté celui mis en œuvre par la poursuite, il n'y a pas i> quelque chose d'équivalent à C # 'C # (Code> Rendement code>, qui était à peu près mon point. Cette question a i> a été posée auparavant.
Si vous rejoignez des itérateurs avec ++ code>, vous obtenez un seul itérateur qui s'exécute sur les deux. Et la méthode
réduceleft code> rejoint utilement une collection complète. Ainsi,
def doIt(i: Int, j: Int, k: Int) = i+j+k
(1 to 2).map(i => {
(1 to 2).map(j => {
(1 to 2).iterator.map(k => doIt(i,j,k))
}).reduceLeft(_ ++ _)
}).reduceLeft(_ ++ _)
Cela ressemble à la meilleure option que j'ai, toujours pas exactement comme le rendement C #, mais c'est plutôt bien. Merci!
Tournez le problème à l'envers. Passez "faire" en tant que fermeture. C'est tout le point d'utiliser une langue fonctionnelle p>
Si vos 3 itérateurs sont généralement petits (c.-à-d., vous pouvez les introduire complètement sans souci de mémoire ni de processeur) et la partie coûteuse est calculée le résultat donné que je, J et K, vous pouvez utiliser la classe de flux de Scala.
def product[A, B, C](a: Iterable[A], b: Iterable[B], c: Iterable[C]): Iterator[(A, B, C)] = { if (a.isEmpty || b.isEmpty || c.isEmpty) Iterator.empty else new Iterator[(A, B, C)] { private val aItr = a.iterator private var bItr = b.iterator private var cItr = c.iterator private var aValue: Option[A] = if (aItr.hasNext) Some(aItr.next) else None private var bValue: Option[B] = if (bItr.hasNext) Some(bItr.next) else None override def hasNext = cItr.hasNext || bItr.hasNext || aItr.hasNext override def next = { if (cItr.hasNext) (aValue get, bValue get, cItr.next) else { cItr = c.iterator if (bItr.hasNext) { bValue = Some(bItr.next) (aValue get, bValue get, cItr.next) } else { aValue = Some(aItr.next) bItr = b.iterator (aValue get, bValue get, cItr.next) } } } } } val stream = product(1 to 3, 1 to 3, 1 to 3).toStream map { case (i, j, k) => i + j + k } stream take 10 foreach println
itérator.zip code> le fera:
Non, cela ne produit pas le produit cartésien qu'une boucle imbriquée.
Je pense que le code ci-dessous est ce que vous cherchez réellement ... Je pense que le compilateur finit par traduire en équivalent du code de carte Rex donné, mais est plus proche de la syntaxe de votre exemple d'origine:
scala> def doIt(i:Int, j:Int) = { println(i + ","+j); (i,j); } doIt: (i: Int, j: Int)(Int, Int) scala> def x = for( i <- (1 to 5).iterator; j <- (1 to 5).iterator ) yield doIt(i,j) x: Iterator[(Int, Int)] scala> x.foreach(print) 1,1 (1,1)1,2 (1,2)1,3 (1,3)1,4 (1,4)1,5 (1,5)2,1 (2,1)2,2 (2,2)2,3 (2,3)2,4 (2,4)2,5 (2,5)3,1 (3,1)3,2 (3,2)3,3 (3,3)3,4 (3,4)3,5 (3,5)4,1 (4,1)4,2 (4,2)4,3 (4,3)4,4 (4,4)4,5 (4,5)5,1 (5,1)5,2 (5,2)5,3 (5,3)5,4 (5,4)5,5 (5,5) scala>
Vous pouvez utiliser un compréhension de séquence sur Itérateurs pour obtenir ce que vous voulez:
for { i <- (1 to 10).view j <- (1 to 10).view k <- (1 to 10).view } yield doFunc(i, j, k)
BTW - S'il y a une manière similaire de le faire en Java ou à toute langue JVM - je serai aussi heureux d'entendre ça.
Dupliqué possible de Scala a équivalent à C # Rendement?