distinct
и distinctBy
оба используют Dictionary
и поэтому требуют хеширования и немного памяти для хранения уникальных предметов.Если ваша последовательность уже отсортирована, вы можете использовать следующий подход (аналогичный вашему).Он почти вдвое быстрее и постоянно использует память, что делает его пригодным для последовательностей любого размера.
let distinctWithoutHash (items:seq<_>) =
seq {
use e = items.GetEnumerator()
if e.MoveNext() then
let prev = ref e.Current
yield !prev
while e.MoveNext() do
if e.Current <> !prev then
yield e.Current
prev := e.Current
}
let items = Seq.init 1000000 (fun i -> i / 2)
let test f = items |> f |> (Seq.length >> printfn "%d")
test Seq.distinct //Real: 00:00:01.038, CPU: 00:00:01.435, GC gen0: 47, gen1: 1, gen2: 1
test distinctWithoutHash //Real: 00:00:00.622, CPU: 00:00:00.624, GC gen0: 44, gen1: 0, gen2: 0
Я не мог найти способ использовать mutable
s вместо ref
s (если не считать ручного кодирования перечислителя), , который, я уверен, значительно ускорит его (я пробовал - без разницы).