Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elixir-lang Finding non-duplicate elements in a list

Tags:

elixir

I'm trying to find non duplicate values from a list e.g.

original list:

iex> list = [2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10]
[2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10]

iex> unique = Enum.uniq(list)
[2, 3, 4, 5, 6, 7, 8, 9, 10]

iex> nondupes = unique -- Enum.uniq(list -- unique)
[2, 3, 5, 7]

result: [2, 3, 5, 7]

I was wondering if there was a better way to achieve this in elixir/erlang

like image 482
Fry Avatar asked Nov 06 '15 13:11

Fry


People also ask

How do I remove duplicates from a list in Elixir?

Thanks to the Enum module, in Elixir we can trivially remove duplicates from a list. In the following example, we take a list of integers and pass it to the Enum.uniq/1 function which removes duplicates from the list without altering the original order of the remaining elements.

How do I prepend an element to a list in Elixir?

An element can be prepended to a list using |: Lists in Elixir are effectively linked lists, which means they are internally represented in pairs containing the head and the tail of a list: Similarly, we could write the list [1, 2, 3] using only such pairs (called cons cells):

How do I concatenate two lists in Elixir?

Linked lists hold zero, one, or more elements in the chosen order. Two lists can be concatenated and subtracted using the Kernel.++/2 and Kernel.--/2 operators: Lists in Elixir are effectively linked lists, which means they are internally represented in pairs containing the head and the tail of a list:

What is the difference between First/2 and first/1 in Elixir?

Returns the first element in list or default if list is empty. first/2 has been introduced in Elixir v1.12.0, while first/1 has been available since v1.0.0. Flattens the given list of nested lists. Empty list elements are discarded. Flattens the given list of nested lists. The list tail will be added at the end of the flattened list.


1 Answers

Another method (not necessarily better) that might be faster for large data is to build a map from elements to their counts and select the ones where count is 1:

list
|> Enum.reduce(%{}, fn (el, acc) -> Dict.put(acc, el, Dict.get(acc, el, 0) + 1) end)
|> Enum.filter(fn {key, val} -> val == 1 end)
|> Enum.map(fn {key, val} -> key end)

This should have runtime O(n * log(n)) instead of the O(n ^ 2) your solution requires (the subtraction should be quadratic if the whole input is unique already).

like image 158
Paweł Obrok Avatar answered Oct 12 '22 19:10

Paweł Obrok