Seq.groupBy:保留原始订单

时间:2012-03-22 15:24:13

标签: dictionary f# enumeration

Dictionary<_,_> - 和Seq.groupBy扩展名 - 似乎按插入顺序枚举元素,但订单正式未定义(请参阅this question)。

这里有一些代码可以证明:

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

我需要一个保证这种行为的分组功能。什么是最好的(consice,有效,惯用,......)方式呢?

修改

这是一种方法:

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])

1 个答案:

答案 0 :(得分: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)