2010-01-19 6 views
26

Ich möchte Stream-Klasse in Scala verwenden, um eine gegebene Liste unendlich zu wiederholen.Scala, wiederhole eine endliche Liste unendlich

Zum Beispiel die Liste (1,2,3,4,5) Ich möchte einen Stream erstellen, der mir gibt (1,2,3,4,5,1,2,3,4,5,1 , 2,3 ....)

So dass ich den Take-Vorgang wickeln kann. Ich weiß, dass dies auf andere Weise implementiert werden kann, aber ich möchte es aus irgendeinem Grund tun, nur Humor mich :)

So ist die Idee, dass mit diesem unendlichen Zyklus aus einer Liste erstellt, kann ich Take-Operation verwenden, und wenn es das Ende der Liste erreicht, wird es zyklisch.

Wie mache ich einen Stream, der einfach eine gegebene Liste wiederholt?

Antwort

33

Sehr ähnlich @ Eastsun ist, aber ein bisschen mehr Absicht aufschlussreich. Getestet in 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) 

Alternativ mit Scalaz: rekursiv

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

Ich mochte diese Antwort am besten, ständig auf dem Stream Companion-Objekt ist wirklich das, was ich gesucht habe. Auch kombiniert mit flatten und tolist bekomme ich genau das, was ich will :) BTW, somestream.join.take (10) .toList, kann jemand näher auf die Notwendigkeit für object.function() Notation und warum es hier benötigt wird? Normalerweise können Sie "seq take 10" haben und etwas wie "seq take 10.toList" funktionieren? – Felix

+0

Ich denke, es ist erwähnenswert, dass "Stream.continually()" war offenbar nicht in früheren Versionen von 2,8 – Felix

+0

In 2.7, "Stream.continually" war "Stream.const" und "streams.flatten" war "Stream.concat (Streams) ' – retronym

1

Stolen blatently von dem ausgezeichneten Scala by Example Buch, Kapitel 12, und mit einigen Änderungen:

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) 

Dies funktioniert für alle Arten Seq (es sei denn, sie können nicht aus mehrfach, natürlich gelesen werden). Ist möglicherweise nicht effizient, wenn der Aufruf von .length langsam ist. Getestet in Scala 2.7.7.

+2

„es sei denn, sie können nicht aus mehrfach gelesen werden, natürlich“ Aber wenn du redest Sequenzen, sollten Sie immer davon ausgehen, dass dies der Fall ist. –

5

Hier ist eine Implementierung, die nicht davon ausgehen, dass length effizient ist:

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

Diese in konstanter Zeit für jeden Seq (einschließlich List oder sogar Stream) und erlegt nur einen konstanten Zeitaufwand jeden aufzufüllen laufen soll Element. Es funktioniert auch für unendliche Sequenzen. So können Sie rep auf einer unendlichen Stream aufrufen und die resultierende Stream wird dem Eingang entsprechen.

7

Es ist eine einfache Art und Weise mit Strom # abflachen in 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

Interessant. Wie funktioniert das? –

+0

Stream.from (0) dient nur dazu, einen unendlichen Strom von Objekten bereitzustellen - jeder andere unendliche Strom von Objekten aller Art würde funktionieren. Sie rufen dann flattern (asTraversable) auf, um jedes Objekt (egal was es ist) in einen Stream umzuwandeln. In diesem Fall verwandelt asTraversable das Objekt in die ursprüngliche Sequenz seq. Es ist eine interessante Möglichkeit, seq ++ seq ++ seq ... –

22

Ein alternatives Verfahren ist die .toStream des Eingangs mit sich selbst verkettet. Das heißt,

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

Ich denke, das ist der beste Ansatz, weil es eine zyklische Struktur erzeugt, die in konstanten Raum passt. –