给定一个项目序列如下:
[ ("a", 1); ("a", 2); ("a", 3); ("b", 1); ("c", 2); ("c", 3) ]
我怎样才能将其懒惰地转换为:
{ ("a", { 1; 2; 3}); ("b", { 1 }); ("c", { 2; 3}) }
您可以假设输入数据源已按分组键元素排序,例如“a”、“b”和“c”。
我在那里使用 { } 来指示它是一个延迟评估的项目序列。
我已经让它通过两个 while 循环强制工作,对源序列的 IEnumerator 进行操作,但这涉及创建引用变量和突变等。我确信有更好的方法可以做到这一点,也许使用递归或使用Seq 库中的一些操作,例如扫描还是展开?
如果你想实施这个IEnumerable<'T>
(使其变得懒惰),那么它必然会有些势在必行,因为IEnumerator<'T>
用于迭代输入的类型是必需的。但其余部分可以使用序列表达式编写为递归函数。
以下在第一级中是惰性的(它惰性地生成每个组),但它不会惰性地生成组的元素(我认为这将具有非常微妙的语义):
/// Group adjacent elements of 'input' according to the
/// keys produced by the key selector function 'f'
let groupAdjacent f (input:seq<_>) = seq {
use en = input.GetEnumerator()
// Iterate over elements and keep the key of the current group
// together with all the elements belonging to the group so far
let rec loop key acc = seq {
if en.MoveNext() then
let nkey = f en.Current
if nkey = key then
// If the key matches, append to the group so far
yield! loop key (en.Current::acc)
else
// Otherwise, produce the group collected so far & start a new one
yield List.rev acc
yield! loop nkey [en.Current]
else
// At the end of the sequence, produce the last group
yield List.rev acc
}
// Start with the first key & first value as the accumulator
if en.MoveNext() then
yield! loop (f en.Current) [en.Current] }
不幸的是,这个(非常有用!)函数不包含在标准 F# 库中,所以如果你想分组adjacent元素(而不是使用列表中的任意元素Seq.groupBy
),你必须自己定义它......
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)