我想對一個序列進行分組,然後在組中的每個元素的第一個出現。當我嘗試這個Seq.groupBy是否在組內保持順序?
Seq.groupBy f inSeq
|> Seq.map (fun (k,s) -> (k,s|>Seq.take 1|>Seq.exactlyOne))
我發現,有時候我得到個不同的元素。這是預期的嗎?
我想對一個序列進行分組,然後在組中的每個元素的第一個出現。當我嘗試這個Seq.groupBy是否在組內保持順序?
Seq.groupBy f inSeq
|> Seq.map (fun (k,s) -> (k,s|>Seq.take 1|>Seq.exactlyOne))
我發現,有時候我得到個不同的元素。這是預期的嗎?
綜觀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
。
如果您看到結果序列的變化,請檢查輸入序列。
謝謝,這是我的預期,但對於某些原因我收到了不同的東西。不幸的是,現在我不能重現這個問題。 –
@RobertSim相反,它一定是「我的機器上的作品」的例子。 – Asti
是的,這是預期的。序列(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
。
......或者在某些情況下,可以使用'Seq.cache'來'固定'seq'(但關閉的行重新建模事物,因爲它們應該保留) –
是的,我應該在第二行使用Seq.head,但我想分享我正在逐字處理的代碼。 :) –
當這種情況發生時,你能隔離這些情況嗎? –