Laser
Laser

Reputation: 5439

How do you get duplicates in a list in elixir?

If you want to get duplicates instead of uniq values in a list, how would you do this in a quick, dense script that uses pattern matching?

For example, with an input of ["ash", "bob", "cat", "bob", "ash"] how could I get ["ash", "bob"] ?

Upvotes: 4

Views: 3269

Answers (4)

tblev
tblev

Reputation: 462

Using Enum.group_by/3

["ash", "bob", "cat", "bob", "ash"]
|> Enum.group_by(&(&1))
|> Enum.filter(&((&1 |> Enum.count()) > 1))
|> Enum.map(&(&1 |> Enum.uniq()))
|> List.flatten()

This method supports searching structs for specific criteria.

Upvotes: 0

Peaceful James
Peaceful James

Reputation: 2235

Here is how I would do it:

["ash", "bob", "cat", "bob", "ash"]
|> (&((&1 -- (&1 |> Enum.uniq())) |> Enum.uniq())).()

This is the same as doing:

my_list = ["ash", "bob", "cat", "bob", "ash"]
(my_list -- (my_list |> Enum.uniq())) |> Enum.uniq()

What is happening:

  1. get a list of all the unique values (the complement to what we want): my_list |> Enum.uniq()
  2. Use list subtraction to get the complement of these unique values.
  3. Use another call to Enum.uniq to get these "duplicates" in unique list.

Upvotes: 1

Paweł Obrok
Paweł Obrok

Reputation: 23164

Since you specified you wanted a quick, dense script, I think you should consider this solution:

l = ["ash", "bob", "cat", "bob", "ash", "ash"]

# to get all duplicates
l -- Enum.uniq(l) # => ["bob", "ash", "ash"]

# to get a unique list of duplicates
Enum.uniq(l -- Enum.uniq(l)) # => ["bob", "ash"]

Upvotes: 12

Laser
Laser

Reputation: 5439

If you want to get a unique list of all duplicates

  def get_uniq_duplicates(all) do
    all |> Enum.reduce({[], []}, fn val, {once, duplicates} -> 
      if once |> Enum.member?(val) do 
        if duplicates |> Enum.member?(val) do
          {once, duplicates}
        else
          {once, duplicates ++ [val]}
        end 
      else
        {once ++ [val], duplicates}
      end
    end) |> elem(1)
  end

If you want a list of duplicates where only one copy of each value has been removed, eg. ["a", "b", "c", "c", "c"] -> ["c", "c"]

Then you can use the simpler:

  def get_duplicates(all) do
    all |> Enum.reduce({[], []}, fn val, {once, duplicates} -> 
      if once |> Enum.member?(val) do 
        {once, duplicates ++ [val]}
      else
        {once ++ [val], duplicates}
      end
    end) |> elem(1)
  end

Upvotes: 0

Related Questions