Map.select and Map.reject

957 views
Skip to first unread message

Erol Fornoles

unread,
Apr 21, 2016, 2:45:21 AM4/21/16
to elixir-lang-core
How useful would it be to have Map.select and Map.reject on the standard lib?

I mostly work with MongoDB, and I usually discard empty key/values (keys with nil/null/{} values) when saving a document. To do this currently, I pipe Enum.reject to Map.new since the former returns a keyword list instead of a Map. And as such, I find it useful to have a select/reject function that both takes and returns a Map.

What do you guys think? I can come up with a basic PR if this is useful.

Gabriel Jaldon

unread,
Apr 21, 2016, 3:16:55 AM4/21/16
to elixir-l...@googlegroups.com
Hi, Erol! Great to see another Filipino around here!

About introducing Map.select and Map.reject, I've no strong opinions about including it to standard lib. If people think it should be included, then rename Map.select to Map.filter so that function names are consistent since there's an Enum.filter. 

Another way to filter out empty values out of a map is to use a comprehension like:
```
for {key, value} <- map, filter.(value) , into: %{}, do: {x, y}
```

The `:into` option ensure you get a Map output just like you want.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/53363f10-a1b7-4dbc-bf12-5a24107f9c40%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Gabe Jaldon

Alexei Sholik

unread,
Apr 21, 2016, 3:50:23 AM4/21/16
to elixir-lang-core
FYI there's :maps.filter() in the Erlang library.

:maps.filter(fn {_key, val} -> not is_empty(val) end, my_map)


Erol Fornoles

unread,
Apr 21, 2016, 3:53:01 AM4/21/16
to elixir-lang-core
That's pretty sweet, thanks for the tip! And I'm also glad to see another Filipino here.

Thank you for pointing out Enum.filter. Coming from a Ruby background, I'm still trying to learn the ropes and the usual idioms as I go along. But I must say that Elixir feels very natural and it's been a relatively easy learning experience for me.

Erol Fornoles

unread,
Apr 21, 2016, 4:08:39 AM4/21/16
to elixir-lang-core
Thanks! This worked for me:

    :maps.filter(fn(_k, v} -> not is_empty(v) end, map)

Is it correct to assume that this should be faster, since we're using a native Erlang function?

José Valim

unread,
Apr 21, 2016, 4:13:57 AM4/21/16
to elixir-l...@googlegroups.com
Thanks! This worked for me:

    :maps.filter(fn(_k, v} -> not is_empty(v) end, map)

Is it correct to assume that this should be faster, since we're using a native Erlang function?

No. Unless the function is a BIF (which means it is implemented in C), you should not see any difference between the same Elixir and Erlang functions. If there are differences, we can always fix them by inlining code.

Erol Fornoles

unread,
Apr 21, 2016, 4:36:42 AM4/21/16
to elixir-lang-core, jose....@plataformatec.com.br
Thanks for the clarification! What do you say about a Map.filter which is just :maps.filter under the hood, with the parameter order switched to support piping?

Peter Hamilton

unread,
Apr 21, 2016, 10:10:48 AM4/21/16
to elixir-lang-core, jose....@plataformatec.com.br

This actually revisits an oldie but goodie. Enum.traverse/2

This still sort of exists with Enum.into/3, I can't quite remember why it was removed, but it used to exist way back in the day. Jose, do you mind jogging my memory on this one?

Enum.traverse_filter or something of the sort would solve this use case in a more general way.


--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Onorio Catenacci

unread,
Apr 21, 2016, 11:03:27 AM4/21/16
to elixir-lang-core, jose....@plataformatec.com.br
We can solve this problem in a fairly generic way as it is right now:

iex> m = %{:a=>1, :b=>2, :c=>3, :d=>4}

iex> s = m |> Enum.filter(fn {k,v} -> rem(v,2) === 0 end)
#=> [b: 2, d: 4]

I'm not sure if this would be easier as a special function in the Map module but, for what it's worth, I don't think it's that tough to manage as it stands right now. Of course that does return a list not a map but that can also be fixed pretty easily as well:

iex> s = m |> Enum.filter(fn {k,v} -> rem(v,2) === 0 end) |> Map.new
#=> %{b: 2, d: 4}

As I say, for whatever it's worth.  I am only pointing this out because I sometimes feel there's a little too much syntactic sugar in Elixir and it can sometimes become a little bit confusing to remember what the desugared versions of certain constructs are. 

--
Onorio


Erol Fornoles

unread,
Apr 21, 2016, 10:49:06 PM4/21/16
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
That's exactly what I've been using up to now: map |> Enum.reject(fun) |> Map.new.

Gabriel mentioned that this could also be done via comprehension. Alexei also pointed out that there's :maps.filter(pred, map), and I am now wondering if it would be beneficial to have Map.filter(map, pred) which would simply be a wrapper to :maps.filter but more pipe friendly.


---

Erol M. Fornoles
Deal Grocer

Email: er...@dealgrocer.com
Skype: erol.fornoles

--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/QVvRVGjLe6w/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/7f9d14a2-e9a7-4d84-9e71-8aeeafe3581a%40googlegroups.com.

Onorio Catenacci

unread,
Apr 22, 2016, 7:50:27 AM4/22/16
to elixir-lang-core
Hi Erol,

It's not my place to say but it seems that just wrapping an Erlang function solely to allow us to pipe into it is probably not the best use of our time. I may be misunderstanding the situation but I believe the general rule has been to avoid rewriting stuff that's already present in Erlang unless there's a compelling reason. I'm not sure being able to pipe into a function qualifies as a "compelling reason".

On the other hand I am being somewhat cavalier about the expression "our time" when I'm not the one volunteering to do the work. :)  I think if you're willing to create a pull request to add this feature, that'd probably be the best way to move forward with this if you want to.  You might also consider putting this in the Crutches library https://github.com/mykewould/crutches which is specifically designed to supplement the standard library with additional utility functions.

Just my humble observations.

--
Onorio



For more options, visit https://groups.google.com/d/optout.

Erol Fornoles

unread,
Apr 22, 2016, 8:41:51 AM4/22/16
to elixir-lang-core
Appreciate you taking the time to explain things. I must admit that I'm quite new to Elixir and and have yet to know the norms and reasoning of the language and community. This helps.

Would definitely take a shot on submitting a PR. :)
Reply all
Reply to author
Forward
0 new messages