Current section
Files
Jump to
Current section
Files
lib/id_set.ex
defmodule IdSet do
@moduledoc """
An IdSet allows you to manage lists containing structs uniquely by id.
Any struct added/deleted must have an id field.
It's different from MapSet in that the comparison is not unique by value but unique by an id field.
"""
@doc """
Adds a struct to a list uniquely by id.
Any duplicate items by id in the list are removed.
Returns an updated list.
## Examples
iex> IdSet.add([], %{id: 1})
[%{id: 1}]
"""
@spec add(List, struct) :: list
def add([], struct) do
[struct]
end
def add(list, nil) do
unique(list, [])
end
def add(list, struct) do
if !member?(list, struct) do
[struct | list]
else
unique(list)
end
end
@doc """
Removes any duplicate structs by id from the list
Returns an updated list.
## Examples
iex> IdSet.unique([%{id: 1}, %{id: 1}])
[%{id: 1}]
"""
@spec unique(List) :: list
def unique(list) do
unique(list, [])
end
defp unique([], acc) do
acc
end
defp unique([element | rest], acc) do
unique(rest, add(acc, element))
end
@doc """
Deletes an item matching the struct.id from the list
Returns an updated list.
## Examples
iex> IdSet.delete([%{id: 1}, %{id: 2}], %{id: 1})
[%{id: 2}]
"""
def delete([], _struct) do
[]
end
def delete(list, %{id: id}) do
Enum.reject(list, fn item -> item.id == id end)
end
@doc """
Checks if the struct exists within the list.
Returns true or false
## Examples
iex> IdSet.member?([%{id: 1}], %{id: 1})
true
iex> IdSet.member?([%{id: 1}], %{id: 2})
false
"""
@spec member?(List, struct) :: boolean
def member?(list, struct) do
find(list, struct)
end
defp find([%{id: id} | _], %{id: id}) do
true
end
defp find([_ | tail], struct) do
find(tail, struct)
end
defp find([], _struct), do: false
end