Are you looking for something like this?
iex(7)> posts
[
%{"has_footnote" => false, "label" => "My Title Without Asterisk"},
%{"has_footnote" => false, "label" => "My Title*"}
]
iex(8)> for %{"label" => title} = p <- posts do
...(8)> if String.ends_with?(title, "*") do
...(8)> %{p | "label" => String.trim_trailing(title, "*"), "has_footnote" => true}
...(8)> else
...(8)> p
...(8)> end
...(8)> end
[
%{"has_footnote" => false, "label" => "My Title Without Asterisk"},
%{"has_footnote" => true, "label" => "My Title"}
]
Note that you don’t have to match the “label” key or even the fact that it’s a map. I just did it so that I could use title
without writing p.title
, but the risk here is that if you have a badly formed collection of posts and some of them don’t have the "label"
key, this actually acts as a filter, which is likely not what you want.
The correct thing, of course, is to not be able to create a post struct like this without having these keys. You can do this using defstruct
and the @enforce_keys
module attribute (or using Vex, Ecto, etc. to have validation and required fields some other way):
defmodule MyApp.Post do
@fields [:label, :has_footnote]
defstruct @fields
@enforce_keys @fields
end
Edit: Of course @kokolegorille has it: You need to simply call the transformation on the list of children you have as well, and as long as they have the needed keys you’ll be fine.