2016-12-29 38 views
4

我想对一个序列进行分组,然后在组中的每个元素的第一个出现。当我尝试这个Seq.groupBy是否在组内保持顺序?

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

我发现,有时候我得到个不同的元素。这是预期的吗?

+0

是的,我应该在第二行使用Seq.head,但我想分享我正在逐字处理的代码。 :) –

+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

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

+0

谢谢,这是我的预期,但对于某些原因我收到了不同的东西。不幸的是,现在我不能重现这个问题。 –

+1

@RobertSim相反,它一定是“我的机器上的作品”的例子。 – Asti

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 

如果要保证确定性b ehaviour,请改用List

+0

......或者在某些情况下,可以使用'Seq.cache'来'固定'seq'(但关闭的行重新建模事物,因为它们应该保留) –

相关问题