9
votes

Comment mettre en œuvre la séquence paresseuse (iTable) dans Scala?

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


2 commentaires

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?


8 Réponses :


7
votes

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)


0 commentaires

-1
votes

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


2 commentaires

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 quelque chose d'équivalent à C # 'C # (Code> Rendement , qui était à peu près mon point. Cette question a a été posée auparavant.



5
votes

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(_ ++ _)


1 commentaires

Cela ressemble à la meilleure option que j'ai, toujours pas exactement comme le rendement C #, mais c'est plutôt bien. Merci!



0
votes

Tournez le problème à l'envers. Passez "faire" en tant que fermeture. C'est tout le point d'utiliser une langue fonctionnelle


0 commentaires

1
votes

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


0 commentaires

0
votes

itérator.zip le fera: xxx


1 commentaires

Non, cela ne produit pas le produit cartésien qu'une boucle imbriquée.



1
votes

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> 


0 commentaires

3
votes

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)


0 commentaires