diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b8c83d..b2fbd51d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Fixed a bug where `list.unique` had quadratic complexity instead of loglinear. - The `bit_array` module gains the `bit_size` and `starts_with` functions. - Ths `string` module gains the `drop_start`, `drop_end`, `pad_start`, `pad_end`, `trim_start`, and `trim_end` functions. These replace the diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam index 61b3c7b5..5537062f 100644 --- a/src/gleam/list.gleam +++ b/src/gleam/list.gleam @@ -1166,10 +1166,18 @@ fn intersperse_loop(list: List(a), separator: a, acc: List(a)) -> List(a) { /// ``` /// pub fn unique(list: List(a)) -> List(a) { - case list { - [] -> [] - [x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))] - } + let #(result_rev, _) = + // We can't use `gleam/set` here, as it would create an import cycle + // (`gleam/set` depends on `gleam/list`), so we're using `gleam/dict` instead. + list + |> fold(#([], dict.new()), fn(acc, x) { + let #(result_rev, seen) = acc + case dict.has_key(seen, x) { + False -> #([x, ..result_rev], dict.insert(seen, x, Nil)) + True -> #(result_rev, seen) + } + }) + result_rev |> reverse } /// Sorts from smallest to largest based upon the ordering specified by a given