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 ad...@a-corp.co.uk 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, jonar...@gmail.com <jonar...@gmail.com> 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 elixir-lang-co...@googlegroups.com. > > 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 elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/50d9b16d-ddd0-4567-b2bb-bbf6fa7f0ca5n%40googlegroups.com.