Seq.groupBy: сохранить оригинальный порядок - PullRequest
0 голосов
/ 22 марта 2012

Dictionary<_,_> - и 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])

1 Ответ

2 голосов
/ 22 марта 2012

Если вы хотите, чтобы последовательность сортировалась по первому появлению каждой клавиши, то вот один из способов сделать это:

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