I would like to give another spin to this proposal:
@doc """
Replaces `old_key` with `new_key` only if `old_key` already exists in `map`.
## Examples
iex> Map.replace_key(%{a: 1, b: 2}, :a, :c)
%{c: 1, b: 2}
iex> Map.replace_key(%{a: 1}, :b, :c)
%{a: 1}
"""
@spec replace_key(map, key, key) :: map
def replace_key(map, old_key, new_key) do
case map do
%{^key => value} ->
map |> delete(old_key) |> put(new_key, value)
%{} ->
map
other ->
:erlang.error({:badmap, other})
end
end
On Monday, October 12, 2020 at 9:37:36 PM UTC+2 [email protected] wrote:
> You could compose a function like this:
>
> ```elixir
> def rename_keys(map, key_mapping) do
> Enum.into(map, %{}, fn {key, value} ->
> {Map.fetch(key_mapping, key), value}
> end)
> end
>
> %{my_map: :is_cool}
> |> rename_keys(%{my_name: :my_new_map})
>
> # => %{my_new_map: :is_cool}
> ```
>
> If you don’t want to put / drop. That way you don’t have to spell out the
> 99-key map, and it’s easy to pipe together with other functions.
>
> It’s also more efficient than the proposed rename_keys would be as you can
> rename multiple keys in one pass.
>
> Adam
>
>
> On 12 Oct 2020, at 16:49, [email protected] <[email protected]> wrote:
>
> > Maybe if you want to keep the other keys as is, then "rename_key" can be
> handy
>
> This is the use case I had in mind. Let's say I have a map with 100 keys,
> but only need to rename one of them. In that event, today I would write
> something like this:
>
> {val, new_map} = Map.pop(original_map, :original_name)
> Map.put(new_map, :new_name, val)
>
> Explicitly defining a new map with 99 keys matching exactly and only one
> changed would be a very large amount of effort, and brittle. With a
> Map.rename_key/2 function, I could write the following, which (to Bruce's
> point) would fit nicely in a pipe chain:
>
> Map.rename_key(original_map, :original_name, :new_name)
>
> > what happens if you add a new key to post? Does it automatically appear
> in the new_map? Or should it not?
>
> The new key should appear in the new map. The only thing that
> Map.rename_key/3 (or Map.rename_keys/3) should do is exchange one key for
> another, without consideration for the rest of the map at all. I enjoy
> using maps where flexibility is more important than the guarantees that the
> strictness of structs. If I were converting one struct to another, I would
> explicitly map each key as in you example above
>
> new_thing = %Thing{
> user_id: post.author_id,
> content: post.body,
> ...
> }
>
> The application of Map.rename_key[s]/3 is more for a proxy application,
> where data is being shuttled from one place to another with a minor
> modification. I may or may not know (or care) what the entirety of the map
> looks like, I simply know that if a given key is present it needs to be
> replaced with a different one.
> On Monday, October 12, 2020 at 7:25:46 AM UTC-4 José Valim wrote:
>
>> Hi everyone,
>>
>> I thought I had commented on this thread but apparently I have not, so
>> apologies for the delay.
>>
>> I am not convinced about this functionality because I honestly do not
>> find this:
>>
>> new_map =
>> post
>> |> Map.rename_key(:user_id, :author_id)
>> |> Map.rename_key(:body, :content)
>>
>> clearer than this:
>>
>> new_map = %{
>> user_id: post.author_id,
>> content: post.body,
>> ...
>> }
>>
>> Maybe if you want to keep the other keys as is, then "rename_key" can be
>> handy, but even then, what happens if you add a new key to post? Does it
>> automatically appear in the new_map? Or should it not?
>>
>> Even if we say that "clearer" is personal, there are practical reasons
>> for preferring the latter, such as the runtime can optimize it better (as
>> all keys are literals and the map is not built dynamically), and it is
>> easier to typecheck maps with known keys.
>>
>> So my $.02 here is that this is not something I would necessarily endorse
>> and, if you really want to rename only certain keys inside a map, you can
>> do it with a helper function or by using put+drop on the desired keys.
>>
>> Thanks!
>>
>>
> --
> 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 [email protected].
>
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/a9edf077-9a58-4e51-af54-cd0732b3fbf3n%40googlegroups.com
>
> <https://groups.google.com/d/msgid/elixir-lang-core/a9edf077-9a58-4e51-af54-cd0732b3fbf3n%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>
>
>
--
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/elixir-lang-core/50d9b16d-ddd0-4567-b2bb-bbf6fa7f0ca5n%40googlegroups.com.