Seq.groupBy是否保留组内的顺序?

时间:2016-12-29 17:08:45

标签: f# sequences

我想对一个序列进行分组,然后对该组中的每个元素进行第一次出现。我试试这个时

Seq.groupBy f inSeq
|> Seq.map (fun (k,s) -> (k,s|>Seq.take 1|>Seq.exactlyOne))

我发现有时候我会从s获得不同的元素。这是预期的吗?

2 个答案:

答案 0 :(得分:4)

是的,这是预料之中的。序列(seq)不保证为pure。您可以定义每次迭代时产生不同值的序列。如果您拨打Seq.take 1两次,可能会得到不同的结果。

作为一个例子,考虑这个序列:

open System

let r = Random ()
let s = seq { yield r.Next(0, 9) }

如果你打电话给Seq.take 1,可能会得到不同的结果:

> s |> Seq.take 1;;
val it : seq<int> = seq [4]
> s |> Seq.take 1;;
val it : seq<int> = seq [1]

使用Seq.head并不能帮助您:

> s |> Seq.head;;
val it : int = 2
> s |> Seq.head;;
val it : int = 6

如果您想保证确定性行为,请改用List

答案 1 :(得分:4)

source of the groupBy implementation - 这是相关的一点:

// Build the groupings

seq |> iter (fun v ->
    let safeKey = keyf v
    let mutable prev = Unchecked.defaultof<_>
    match dict.TryGetValue (safeKey, &prev) with
    | true -> prev.Add v
    | false ->
        let prev = ResizeArray ()
        dict.[safeKey] <- prev
        prev.Add v)

迭代源数组并将值添加到键的相应列表中。子序列的顺序直接受输入序列的顺序影响。对于相同的输入序列,我们可以期望groupBy返回相同的输出序列。这就是为groupBy编码测试的方式。

如果您在结果序列中看到变化,请检查输入序列。