是否存在F#的Seq.groupBy函数的懒惰版本?

时间:2015-05-09 01:39:14

标签: linq f# lazy-evaluation lazy-sequences

我想使用如下代码懒惰地对一个非常大的序列进行分组:

// native F# version
let groups =
    Seq.initInfinite id
        |> Seq.groupBy (fun i -> i % 10)
for (i, group) in groups |> Seq.take 5 do
    printfn "%A: %A" i (group |> Seq.take 5)

预期输出为:

1: seq [1; 11; 21; 31; ...]
2: seq [2; 12; 22; 32; ...]
3: seq [3; 13; 23; 33; ...]
4: seq [4; 14; 24; 34; ...]
5: seq [5; 15; 25; 35; ...]

然而,在实践中,这个程序无限循环,什么都不打印。是否有可能在F#中实现这一目标?

我愿意使用Linq而不是本机函数,但GroupBy和ToLookup都会产生相同的行为(即使Linq的GroupBy应该是懒惰的):

// Linq version
let groups =
    Enumerable.GroupBy(
        Seq.initInfinite id,
        (fun i -> i % 10))
for group in groups |> Seq.take 5 do
    printfn "%A" (group |> Seq.take 5)

也许我无意中做了一些引起急切评价的事情?

2 个答案:

答案 0 :(得分:2)

有两件事要说:

首先,你怎么知道,无限序列中会有多少组?换句话说,您需要实现多少项才能从上方获得5组?如果你要求11组,你需要实现多少?从概念上讲,非正式地解释,当你懒洋洋地分组时会发生什么。

其次,group by的Rx版本是懒惰的,可能与你想要的一样接近:http://rxwiki.wikidot.com/101samples#toc24这个版本的group by,因为它对每个元素做出反应并激活相应的组因此,当一个新元素被消耗时,你会得到一个事件,并且你得到它发生在哪个组中的信息,而不是获取一个组列表。

答案 1 :(得分:1)

我对F#的Hopac库有一个所谓的choice streamspresentation)的实现,它们既是惰性的又是并发/异步的,并且还提供groupBy操作。