How to filter a list of nils

I have sometimes list with elements of different type.
for example nil and tuple
the thing is that the filter function is a bit long. I wonder if this can be written shorter. particularly because i don’t care about failing cases.

Enum.filter(list_of_nils_and_tuples, fn elem ->
        if(is_nil(elem)) do
          false
        else
          {id, _v} = elem
            some_complicated_test(id)
        end
      end)

The question is maybe more about how to avoid if else structures in elixir?

Pattern matching to the rescue!

Enum.filter(list_of_nils_and_tuples, fn 
  nil -> false
  {id, _v}  -> some_complicated_test(id)
end)
2 Likes

ah thanks forgot about pattern matching in unnamed functions.
I guess there is no chance to get rid of the
fn nil -> false end
part, right?
I am thinking about it because the documentation for filter says:

Blockquote
Filters the enumerable , i.e. returns only those elements for which fun returns a truthy value.

So I thought it might maybe be possible to let things be “falthy” without declaring them false.

Another option is to to use a comprehension:

for {id, _v} = nil_or_tuple <- list_of_nils_and_tuples, not is_nil(nil_or_tuple), do: some_complicated_test(id)
1 Like

You can, but You also apply a transformation at the same time…

list_of_nils_and_tuples
|> Enum.filter(& &1)     # drop falsy value
|> Enum.map(& some_complicated_test(elem(&1, 0)))

You can also define some_complicated_test to return false when nil is passed, and use it as the filter function.

2 Likes

You can also filter/reject multiple times, though you may want to use stream instead of enum for longer lists.

list_of_nils_and_tuples
|> Enum.reject(&is_nil/1)
|> Enum.filter(fn {id, _v} -> some_complicated_test(id) end)
1 Like