Scala,无限重复有限列表

Posted

技术标签:

【中文标题】Scala,无限重复有限列表【英文标题】:Scala, repeat a finite list infinitely 【发布时间】:2011-01-07 01:24:08 【问题描述】:

我想在 scala 中使用 Stream 类来无限重复给定的列表。

例如列表 (1,2,3,4,5) 我想创建一个流给我 (1,2,3,4,5,1,2,3,4,5,1, 2,3....)

这样我就可以包装 take 操作。我知道这可以通过其他方式实现,但出于某种原因我想这样做,请幽默:)

所以想法是,通过从某个列表创建这个无限循环,我可以使用 take 操作,当它到达列表的末尾时,它会循环。

如何制作一个简单重复给定列表的流?

【问题讨论】:

【参考方案1】:

另一种方法是将输入的.toStream 与自身递归连接。也就是说,

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

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

【讨论】:

我认为这是最好的方法,因为它会生成一个适合恒定空间的循环结构。 小调整。为了让这个技巧编译 xs 应该是一个按名称赋值 def xs: Stream[Int] = ... 在 Scala 2.13+ 中使用 LazyList 代替 Stream 也可以做到这一点 回想起来,val 版本似乎可以在 Scala 2.12 中编译。也许该示例应该更新为使用 2.13 LazyList,这确实需要使用 def @SethTisue,如果你的意思是它有确定的大小,相应的 API 要求不同【参考方案2】:

与@Eastsun 的非常相似,但更能透露一些意图。在 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)

或者,使用 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)

【讨论】:

我最喜欢这个答案,一直在 Stream 伴生对象上确实是我一直在寻找的。还结合 flatten 和 tolist 我得到了我想要的 :) BTW,somestream.join.take(10).toList,有人可以详细说明 object.function() 表示法的需要以及为什么需要它吗?通常你可以有“seq take 10”,像“seq take 10.toList”这样的工作吗? 我认为值得注意的是,“Stream.continually()”显然不存在于 2.8 之前的版本中 在 2.7 中,Stream.continuallyStream.conststreams.flattenStream.concat(streams) 也许你可以移动带有和不带有'.'的方法调用的比较。到一个新问题。 我认为值得注意的是,Stream.continually(...).flatten 方法会导致具有无限潜在空间消耗的重复结构,而不是适合恒定空间的循环结构(如 Volcan 的回答)。【参考方案3】:

在 scala 2.8 中有一个使用 Stream#flatten 的简单方法

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)

【讨论】:

Stream.from(0) 只是为了提供无限的对象流 - 任何其他任何类型的无限对象流都可以工作。然后调用 flatten(asTraversable) 将每个对象(无论它是什么)转换为流。在这种情况下,asTraversable 将对象转换为原始序列 seq。这是 seq ++ seq ++ seq 的一种有趣的方式...【参考方案4】:

这是一个不假设 length 有效的实现:

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)

这对于任何Seq(包括List 甚至Stream)都应该在恒定时间内运行,并且只会施加恒定的时间开销来填充每个元素。此外,它甚至适用于无限序列。因此,您可以在无限的Stream 上调用rep,得到的Stream 将等同于输入。

【讨论】:

【参考方案5】:

从优秀的Scala by Example 书籍第 12 章中公然窃取,并进行了一些修改:

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)

这适用于所有 Seq 类型(当然,除非它们不能被多次读取)。如果 .length 调用很慢,可能效率不高。在 Scala 2.7.7 中测试。

【讨论】:

“当然,除非它们不能被多次读取”但是当你谈论序列时,你应该总是假设是这种情况。

以上是关于Scala,无限重复有限列表的主要内容,如果未能解决你的问题,请参考以下文章

Scala在列表中找到重复项

检查列表中的偶数,并在 Scala 中获得类型不匹配 [重复]

当应用程序移至后台状态并再次移至前台状态时,无限列表会导致重复

有限与无限思想

Scala可变参数列表,命名参数和参数缺省

在 vuejs 中使用 v-for 时无限重复