我想对一个序列进行分组,然后对该组中的每个元素进行第一次出现。我试试这个时
Seq.groupBy f inSeq
|> Seq.map (fun (k,s) -> (k,s|>Seq.take 1|>Seq.exactlyOne))
我发现有时候我会从s获得不同的元素。这是预期的吗?
答案 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
编码测试的方式。
如果您在结果序列中看到变化,请检查输入序列。