Creating smaller list from enum.Map() leads to lots of nil values

Hello,

I’m trying to create a new list from a map I’m given like so

Enum.map(params, fn {k,v} -> if String.contains?(k, "checklist") and v != "", do: v end)

but the result is list = [nil,nil,nil,nil, 5,3,2] when I just want it to be [5,3,2]. Is there a way to get this result?

Enum.filter/2 after mapping.

Something like this:

params
|> Enum.map(fn {k, v} -> String.contains?(k, "checklist") and v != "", do: v end)
|> Enum.filter(&(&1 != nil))

Or, to reduce the conditionals, turn it around like this:

params
|> Enum.filter(fn {k, v} -> String.contains?(k, "checklist") and v != "" end)
|> Enum.map(fn {_, v} -> v end)
2 Likes

@NobbZ very cool.

What does the (&(&1 != nil)) denote in your first example?

Its creating an anonymous function using the capture operator.

It is equivalent to fn x -> x != nil end but less verbose if you don’t need pattern matching.

1 Like

Enum.reject(&is_nil/1)?

3 Likes

Use Kernel.SpecialForms.for/1 comprehension.

for {k, v} <- params, String.contains?(k, "checklist"), v != "", do: v
7 Likes

Yeah I’d use either for or flat_map. map and filter are both just special-cases of the generic flat_map, which can do both all at once and it is single-pass:

params
|> Enum.flat_map(fn {k, v} -> if(String.contains?(k, "checklist") and v != "", do: [v], else: []) end)

And @mudasobwa’s for is great. :slight_smile:

4 Likes

@mudasobwa @NobbZ never thought such a simple question could teach me so much about elixir. Thanks a ton

1 Like