stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

`list.unique` needs quadratic time

Open radekm opened this issue 6 months ago • 1 comments

Hello. According to the documentation list.unique returns in loglinear time.

But it's implementation

pub fn unique(list: List(a)) -> List(a) {
  case list {
    [] -> []
    [x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))]
  }
}

is quadratic instead. It's especially slow if list is already unique or almost unique.

I believe that the following implementation is faster (if set.contains and set.insert are logarithmic):

pub fn unique(xs: List(a)) -> List(a) {
  let #(result_rev, _) =
    xs
    |> list.fold(#([], set.new()), fn(acc, x) {
      let #(result_rev, seen) = acc
      case set.contains(seen, x) {
        False -> #([x, ..result_rev], set.insert(seen, x))
        True -> #(result_rev, seen)
      }
    })
  result_rev |> list.reverse
}

radekm avatar Aug 06 '24 13:08 radekm