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.continually
是 Stream.const
和 streams.flatten
是 Stream.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 中获得类型不匹配 [重复]