我想使用如下代码懒惰地对一个非常大的序列进行分组:
// 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)
也许我无意中做了一些引起急切评价的事情?
答案 0 :(得分:2)
有两件事要说:
首先,你怎么知道,无限序列中会有多少组?换句话说,您需要实现多少项才能从上方获得5组?如果你要求11组,你需要实现多少?从概念上讲,非正式地解释,当你懒洋洋地分组时会发生什么。
其次,group by的Rx版本是懒惰的,可能与你想要的一样接近:http://rxwiki.wikidot.com/101samples#toc24这个版本的group by,因为它对每个元素做出反应并激活相应的组因此,当一个新元素被消耗时,你会得到一个事件,并且你得到它发生在哪个组中的信息,而不是获取一个组列表。
答案 1 :(得分:1)
我对F#的Hopac库有一个所谓的choice streams(presentation)的实现,它们既是惰性的又是并发/异步的,并且还提供groupBy操作。