【发布时间】:2014-03-25 11:45:18
【问题描述】:
如果我有一个Seq,那么很容易生成到给定长度限制的所有子序列,如下所示:
def subseqs[A](n: Int)(s: Seq[A]) = {
(1 to n).flatMap(s.sliding)
}
subseqs(3)(List(1, 2, 3, 4)) foreach println //> List(1)
//| List(2)
//| List(3)
//| List(4)
//| List(1, 2)
//| List(2, 3)
//| List(3, 4)
//| List(1, 2, 3)
//| List(2, 3, 4)
但是,是否有一种惯用的(并且相当有效)方法可以将迭代器作为输入,产生一个迭代器(或者可能是一个流)作为输出?
更新:我有一个实现迭代器的working implementation,它在一次传递中完成,因此需要很少的内存,但相对较长并且使用可变变量(var 和 @ 987654325@) - 如果有帮助,可以发布。我希望有一种更优雅的方式使用高阶函数...
上面的方法(使用sliding())不起作用,因为迭代器在第一遍就用完了,不能再使用了。
使用sliding() 和inits() 的组合更好,但会错过预期子序列的尾部:
def subseqsi[A](n: Int)(i: Iterator[A]) = {
//(1 to n).flatMap(i.sliding)
// no - this exhausts the iterator
i.sliding(n).flatMap { _.inits.filterNot(_.isEmpty) }
//nearly, this misses off subsequences towards the end
}
//> List(1, 2, 3)
//| List(1, 2)
//| List(1)
//| List(2, 3, 4)
//| List(2, 3)
//| List(2)
我的输入数据是一个未知(可能非常大)大小的迭代器。输出子序列的顺序无关紧要。
【问题讨论】:
-
这是我以前用 Haskell 写的一个高尔夫球。我将给出 Haskell 代码并将其翻译成 Scala 留给读者 :)
init . tails <=< tail . inits适用于有限列表和无限列表,所以它必须通过构造变得懒惰! fish/<=<运算符来自Control.Monad,是Kleisli组成。
标签: scala functional-programming iterator