2012-03-22 108 views
0

Dictionary<_,_> -and Seq.groupBy通過伸展出現枚舉元素中的插入順序,然而順序是正式未定義(見this question)。Seq.groupBy:保留原始順序

下面是一些代碼來演示:

let groupByPreservesOrder l = 
    let l2 = 
    l 
    |> Seq.groupBy id 
    |> Seq.map fst 
    |> Seq.toList 
    (l = l2) 

let l = List.init 1000 (fun i -> 
    if i % 2 <> 0 then -(i) else i/2) 

groupByPreservesOrder l //true 

我需要一組功能保證此行爲。什麼是最好的(認真,高效,慣用,...)的方式去做呢?

編輯

下面是做這件事:

let groupByStable f items = 
    let items = items |> Seq.map (fun x -> f x, x) |> Seq.toList 
    let d = items |> Seq.groupBy fst |> dict 
    items 
    |> Seq.distinctBy fst 
    |> Seq.map (fun (k, _) -> k, Seq.map snd d.[k]) 
+0

我是啞巴還是這個問題有點混亂? – ChaosPandion 2012-03-22 15:27:55

+0

如果你需要它*保證*我想你要麼必須自己實施或使用(一些)'Seq.order'調用 – Carsten 2012-03-22 15:29:16

+0

@ChaosPandion:我不確定。 :-) – Daniel 2012-03-22 15:30:51

回答

2

如果你想確保序列是由每個鍵的首次亮相排序,那麼這裏做到這一點的一種方法:

let groupByOP f s = 
    s 
    |> Seq.mapi (fun i x -> i,x) 
    |> Seq.groupBy (snd >> f) 
    |> Seq.sortBy (snd >> Seq.map fst >> Seq.min) 
    |> Seq.map (fun (k,vs) -> k, vs |> Seq.map snd) 

如果你還想每個組按初始放置排序,那麼我認爲這樣的事情應該工作:

let groupByOP f s = 
    s 
    |> Seq.mapi (fun i x -> i,x) 
    |> Seq.groupBy (snd >> f) 
    |> Seq.map (fun (k,vs) -> k, vs |> Seq.sortBy fst) 
    |> Seq.sortBy (snd >> Seq.head >> fst) 
    |> Seq.map (fun (k,vs) -> k, vs |> Seq.map snd) 
+0

Doh! 15秒後**完全相同的代碼(並且不僅僅是語義相同,而是字面相同!) – 2012-03-22 15:58:08

+0

文檔不能保證它,但我們知道'Seq.groupBy'保留了每個組內的值的順序,所以你的第一個功能應該做的伎倆。我添加了另一個可能的解決方案,它的表現與你的相似。你知道它與你的實際區別嗎? – Daniel 2012-03-22 18:29:28

+0

功能組合真的讓我頭疼:)我花了5分鐘來找出什麼snd >> Seq.map fst >> Seq.min試圖完成。 – 2015-12-01 00:03:40