Проблема в том, что возвращаемый результат отсортирован?Этот алгоритм будет работать линейно над входной последовательностью.Просто индексы нужно отсортировать.Если последовательность большая, но индексов не так много - это будет быстро.Сложность: N -> Макс (индексы), M -> количество индексов: O (N + MlogM) в худшем случае.
let seqTakeIndices indexes =
let rec gather prev idxs xs =
match idxs with
| [] -> Seq.empty
| n::ns -> seq { let left = xs |> Seq.skip (n - prev)
yield left |> Seq.head
yield! gather n ns left }
indexes |> List.sort |> gather 0
Вот вариант List.fold, но более сложныйчитать.Я предпочитаю первое:
let seqTakeIndices indices xs =
let gather (prev, xs, res) n =
let left = xs |> Seq.skip (n - prev)
n, left, (Seq.head left)::res
let _, _, res = indices |> List.sort |> List.fold gather (0, xs, [])
res
Добавлено: Все еще медленнее, чем ваш вариант, но намного быстрее, чем мои старые варианты.Из-за неиспользования Seq.skip, который создает новые перечислители и сильно замедляет работу.
let seqTakeIndices indices (xs : seq<_>) =
let enum = xs.GetEnumerator()
enum.MoveNext() |> ignore
let rec gather prev idxs =
match idxs with
| [] -> Seq.empty
| n::ns -> seq { if [1..n-prev] |> List.forall (fun _ -> enum.MoveNext()) then
yield enum.Current
yield! gather n ns }
indices |> List.sort |> gather 0