2012-03-22 88 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