2016-12-29 65 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'(但關閉的行重新建模事物,因爲它們應該保留) –

相關問題