Announcing Nested Filter: v0.1.5
Last update: 10/24/17
This post is about a package I made called nested_filter, the background behind it, and what I learned from it.
API calls and the motivation behind Nested Filter
This all came about due to another Elixir package I started building called yt_potion. I started using structs with default parameters (usually set to nil). But the issue was that passing nil values meant the YouTube API would return an error response.
So I had to figure out a way to filter out all the nil and other values causing this issue.
The Problem in Code
To give you an idea of the problem, here is a code snippet of the functionality I would like from Map.drop in Elixir:
nested_map = %{a: 1, b: %{c: nil, d: nil}, c: nil}
Map.drop(nested_map, [:c, :d])
# => %{a: 1, b: %{c: nil, d: nil}}
# But you actually wanted:
# => %{a: 1}
The Current API
Right now there are 2 methods – drop_by_value and drop_by_key. The full API is documented in the README of the GitHub page.
To give you an idea, here is an example of using drop_by_value:
# Remove the nil values from a nested map, preserving empty map values
nested_map = %{a: 1, b: %{m: nil, n: 2}, c: %{p: %{q: nil, r: nil}, s: %{t: 2, u: 3}} }
NestedFilter.drop_by_value(nested_map, [nil])
# => %{a: 1, b: %{n: 2}, c: %{p: %{}, s: %{t: 2, u: 3}} }
Why I Released This As An Elixir Package
My reason for releasing this was two-fold. One was to help solve my problem in calling the YouTube API . The other was to get more familiar with Elixir conventions and learn something new.
What I Learned By Releasing This Package
One thing I learned is how helpful the Elixir community is. I got a great critique from scohen and learned the following from that critique.
Cond is less “idiomatic” than case
Don’t do this:
cond do
is_map(map) ->
map
|> Enum.any?(fn{key, _} -> is_map(map[key]) end)
true ->
false
end
Prefer this:
case map do
%{} ->
|> Enum.any?(map, fn {_key, val} -> is_map(val) end)
_ ->
false
end
Prefer pattern matching to conditionals
Instead of doing the above conditional matching, use pattern matching via functions.
defp is_nested_map?(map) when is_map(map) do
Enum.any?(map, fn {key, _} -> is_map(map[key]) end)
end
defp is_nested_map?(_), do: false
Idiomatic Naming – Filter vs Reject
In Elixir, filter means you want to keep items and reject means you want to remove them. So name things in your code accordingly.
Summary
The Elixir community seems really friendly and helpful. Feel free to ask people questions in order to level up.
I learned quite a bit from making and releasing nested_filter. The Elixir community is helpful and I look forward to learning more about Elixir.