2010-01-19 8 views
26

Je veux utiliser la classe Stream dans scala pour répéter indéfiniment une liste donnée.Scala, répète une liste infinie infiniment

Par exemple la liste (1,2,3,4,5) Je veux créer un flux qui me donne (1,2,3,4,5,1,2,3,4,5,1 , 2,3 ....)

Pour que je puisse envelopper l'opération de prise. Je sais que cela peut être mis en œuvre d'autres façons, mais je veux le faire de cette façon pour une raison quelconque, juste humour moi :)

Donc l'idée est que, avec ce cycle infini créé à partir d'une liste, je peux utiliser prendre opération, et quand il atteint la fin de la liste il cycles.

Comment créer un flux qui répète simplement une liste donnée?

Répondre

33

Très similaire à @ Eastsun de, mais un peu plus l'intention révélatrice. Testé en Scala 2.8.

scala> val l = List(1, 2, 3) 
l: List[Int] = List(1, 2, 3) 

scala> Stream.continually(l.toStream).flatten.take(10).toList 
res3: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1) 

En variante, avec Scalaz:

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> val l = List(1, 2, 3) 
l: List[Int] = List(1, 2, 3) 

scala> l.toStream.repeat[Stream].join.take(10).toList 
res7: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1) 
+1

J'ai aimé cette réponse le mieux, continuellement sur l'objet compagnon Stream est vraiment ce que je cherchais. Aussi combiné avec aplatir et tolist je reçois exactement ce que je veux :) BTW, somestream.join.take (10) .toList, quelqu'un peut élaborer sur le besoin de notation object.function() et pourquoi il est nécessaire ici? Habituellement, vous pouvez avoir "seq prendre 10", et quelque chose comme "se faire prendre 10.toList" fonctionne? – Felix

+0

Je pense qu'il vaut la peine de noter que "Stream.continually()" n'était apparemment pas présent dans les versions précédentes de 2.8 – Felix

+0

Dans 2.7, 'Stream.continually' était' Stream.const' et 'streams.flatten' était' Stream.concat (flux) ' – retronym

1

volé blatently de l'excellent livre Scala by Example, chapitre 12, et avec quelques modifications:

def repeatedSeq(idx: Int, lst:Seq[Int]): Stream[Int] = Stream.cons(lst(idx), repeatedSeq((idx + 1)%lst.length, lst)) 

for(i <- repeatedSeq(1,List(1,1,2,3,5))) println(i) 

Cela fonctionne pour tous les types Seq (à moins qu'ils ne peuvent pas être lus à partir de plusieurs fois, bien sûr). Peut ne pas être efficace si l'appel .length est lent. Testé à Scala 2.7.7.

+2

« à moins qu'ils ne peuvent pas être lus à partir de plusieurs fois, bien sûr » Mais quand vous parlez de séquences, vous devriez toujours supposer que ce soit le cas. –

5

est ici une mise en œuvre qui ne suppose pas que length est efficace:

def rep[A](seq: Seq[A]) = { 
    def inner(proj: Seq[A]): Stream[A] = { 
    if (proj.isEmpty) 
     inner(seq) 
    else 
     Stream.cons(proj.first, inner(proj drop 1)) 
    } 

    if (seq.isEmpty) 
    Stream.empty 
    else 
    inner(seq) 
} 

Cela devrait fonctionner en temps constant pour tout Seq (y compris List ou même Stream) et impose seulement une surcharge de temps constant pour remplir chaque élément. En outre, cela fonctionne même pour des séquences infinies. Ainsi, vous pouvez appeler rep sur un Stream infini et le résultat Stream sera équivalent à l'entrée.

7

Il y a une façon simple aveC# Stream aplatissent dans scala 2,8

Welcome to Scala version 2.8.0.r20542-b20100116020126 (Java HotSpot(TM) Client VM, Java 1.6.0_18). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> def cycle[T](seq: Seq[T]) = Stream.from(0).flatten(_ => seq) 
cycle: [T](seq: Seq[T])scala.collection.immutable.Stream[T] 

scala> cycle(1::2::3::Nil) 
res0: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

scala> res0.take(10) 
res1: scala.collection.immutable.Stream[Int] = Stream(1, ?) 

scala> res0.take(10).toList 
res2: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1) 
+1

Intéressant. Comment ça marche? –

+0

Stream.from (0) est juste pour fournir un flux infini d'objets - tout autre flux infini d'objets de tout type fonctionnerait. Vous appelez ensuite flatten (asTraversable) pour transformer chaque objet (quel qu'il soit) en flux. Dans ce cas, asTraversable transforme l'objet en séquence d'origine seq. C'est une façon intéressante de faire seq ++ seq ++ seq ... –

22

Une autre méthode est la concaténation des .toStream de l'entrée avec lui-même de façon récursive. C'est,

scala> val xs: Stream[Int] = List(1, 2, 3).toStream #::: xs 
xs: Stream[Int] = Stream(1, ?) 

scala> xs.take(10).toList 
res1: List[Int] = List(1, 2, 3, 1, 2, 3, 1, 2, 3, 1) 
+2

Je pense que c'est la meilleure approche, car elle génère une structure cyclique qui tient dans l'espace constant. –

Questions connexes