Prefix/Suffix map keys proposal

31 views
Skip to first unread message

Tiago Botelho

unread,
Sep 20, 2019, 9:07:41 AM9/20/19
to elixir-lang-core
A common pattern that I've found myself using is having to prefix a few keys (namely `ids`) which I do with following approach:

```
%{}
|> Map.put(:prefix_key_1, map.key_1)
|> Map.put(:prefix_key_2, map.key_2)

=> %{prefix_key_1: :val_1, prefix_key_2: :val_2}
```

or 

```
%{prefix_key_1: map.key_1, prefix_key_2: map.key_2}

=> %{prefix_key_1: :val_1, prefix_key_2: :val_2}
```

It seems to me that we already have good functionality for taking specific keys out of a map by using Map.take/2 
(which is effectively the same thing we are doing in the examples above) but no good way of bulk updating specific key names.

My proposal would be to be able to pass a `prefix` as an option to `Map.take` which would look roughly like the following:

```
Map.take(map, [:key_1, :key_2, :key_3], prefix: :prefix)

=> %{prefix_key_1: :val_1, prefix_key_2: :val_2, prefix_key_3: :val_3}
```

Pros:

* A simpler interface to take keys from a map and "rename" them according to the context they will be used for

Cons:

* Using the `prefix` option would mean that all the keys would get prefixed, a mixed approach would still require the examples showed above.
* Might make Map.take do too much at once 

Since the Cons might be might seem to discourage this approach, another proposal would be to introduce Map.prefix/2 and Map.suffix/2 which would only
update the chosen keys in a map like so:

     
     ```
     map
     |> Map.take([:key_1, :key_2, :key_3, :key_4])
     |> Map.prefix([:key_3, :key_4], :prefix)

     => %{key_1: :val_1, key_2: val_2, prefix_key_3: :val_3, prefix_key_4: :val_4}
    ```

Interested in hearing your thoughts 😊

Thank you,
Tiago

Alexei Sholik

unread,
Sep 20, 2019, 10:17:08 AM9/20/19
to elixir-lang-core
It's functionality that is very specific to a particular use case to be added to a standard library module. Plus, it either needs to create new atoms (which standard library will never do) or fail for some inputs (which is again not generally useful):

iex(1)> m = %{key_1: :val_1, key_2: :val_2}
iex(4)> m |> Map.take([:key_1, :key_2]) |> Map.new(fn {key, val} -> {String.to_existing_atom("prefix_#{key}"), val} end)
** (ArgumentError) argument error
    :erlang.binary_to_existing_atom("prefix_key_1", :utf8)
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:888: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:240: :erl_eval.expr/5
    (elixir) lib/map.ex:216: Map.new_transform/3
iex(4)> :prefix_key_1
:prefix_key_1
iex(5)> :prefix_key_2
:prefix_key_2
iex(6)> m |> Map.take([:key_1, :key_2]) |> Map.new(fn {key, val} -> {String.to_existing_atom("prefix_#{key}"), val} end)

%{prefix_key_1: :val_1, prefix_key_2: :val_2}
--
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/d7ee27af-814a-419e-8b3c-280fbad4191e%40googlegroups.com.

Tiago Botelho

unread,
Sep 20, 2019, 10:44:03 AM9/20/19
to elixir-lang-core
That is a great point, thank you for clarifying! 😊

Allen Madsen

unread,
Sep 20, 2019, 10:44:42 AM9/20/19
to elixir-l...@googlegroups.com
One other note, not all keys are atoms. Any term can be used as a key.


Reply all
Reply to author
Forward
0 new messages