Scala, repeat a finite list infinitely

2019-03-09 05:22发布

I want to use Stream class in scala to repeat a given list infinitely.

For example the list (1,2,3,4,5) I want to create a stream that gives me (1,2,3,4,5,1,2,3,4,5,1,2,3....)

So that I can wrap the take operation. I know this can be implemented in other ways, but I wanna do it this way for some reason, just humor me :)

So the idea is that with this infinite cycle created from some list, I can use take operation, and when it reaches the end of the list it cycles.

How do I make a stream which simply repeats a given list?

5条回答
Viruses.
2楼-- · 2019-03-09 05:45

Very similar to @Eastsun's, but a bit more intention revealing. Tested 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)

Alternatively, with 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)
查看更多
我想做一个坏孩纸
3楼-- · 2019-03-09 05:46

There is a simple way with Stream#flatten 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)
查看更多
手持菜刀,她持情操
4楼-- · 2019-03-09 05:47

An alternative method is concatenating the .toStream of the input with itself recursively. That is,

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)
查看更多
倾城 Initia
5楼-- · 2019-03-09 05:50

Stolen blatently from the excellent Scala by Example book, chapter 12, and with a few 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)

This works for all Seq types (unless they can't be read from multiple times, of course). Might not be efficient if the .length call is slow. Tested in Scala 2.7.7.

查看更多
【Aperson】
6楼-- · 2019-03-09 05:56

Here's an implementation which doesn't assume that length is efficient:

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

This should run in constant time for any Seq (including List or even Stream) and only imposes a constant time overhead to populate each element. Also, it works even for infinite sequences. So, you can call rep on an infinite Stream and the resulting Stream will be equivalent to the input.

查看更多
登录 后发表回答