Reputation: 664
I have a collection of records from a data source denoting {:person, _} for person, {:dog, _} for dog, etc. I'd like to return a modified version of the record based on the condition that the record is that of ':person'.
db = [
{:dog, %{name: "Sparky", age: 4}},
{:person, %{name: "Jeff", age: 34}},
{:person, %{name: "Suzan", age: 41}},
{:dog, %{name: "Bella", age: 8}}
]
I'd like to return:
[{:person, "Jeff", 34}, {:person, "Suzan", 41}]
I've tried:
db |> Enum.map(fn {:person, data} -> {:person, data.name, data.age} end)
But I'm erroring on non-match for :dog
Any advice?
Upvotes: 1
Views: 95
Reputation: 2882
One easy way to do this is by using a Comprehension.
for {:person, data} <- db, do: {:person, data.name, data.age}
Comprehensions are a powerful tool in Elixir that allow you to filter out data from a list with a match spec (among other things). The above code snippet will only iterate over items in the list that are 2 element tuples, having the first element be the :person
atom. All other entries are filtered out. Of course, comprehensions are more powerful than this. If you wanted to enforce that all records returned included a name and age attribute you could do something like this:
for {:person, %{age: age, name: name}} <- db,
is_integer(age),
is_binary(name),
do: {:person, name, age}
The above will only return entries that are 2 element tuples, having :person
as the first element, :age
and :name
keys in the data, and where age is an integer and name is a binary.
Upvotes: 4
Reputation: 94
First You need to filter out elements You want to use, so it should be like this
db |> Enum.filter(fn data -> match?({:person, _}, data) end)
|> Enum.map(fn {:person, data} -> {:person, data.name, data.age} end)
Map is just taking input elements and creates new Enum with returned values from function given as argument to map function.
Filter creates new Enum which contains only element where given function return true
Upvotes: 2