iamacube

iamacube

Rename all map keys

Hi! I have a list of maps and I want to rename the keys.

What I have:

[info] entities: [ok: %{"Email Address [Required]" => "fblue@mikasa.com", "First Name [Required]" => "Blue", "Last Name [Required]" => "First"}, ok: %{"Email Address [Required]" => "sred@mikasa.com", "First Name [Required]" => "Red", "Last Name [Required]" => "Second"}, ok: %{"Email Address [Required]" => "tyellow@mikasa.com", "First Name [Required]" => "Yellow", "Last Name [Required]" => "Third"}]

What I want to achieve:

[info] entities: [ok: %{"email" => "fblue@mikasa.com", "first_name" => "Blue", "last_name" => "First"}, ok: %{"email" => "sred@mikasa.com", "first_name" => "Red", "last_name" => "Second"}, ok: %{"email" => "tyellow@mikasa.com", "first_name" => "Yellow", "last_name" => "Third"}]

First Name [Required] to first_name
Last Name [Required] to last_name
Email Address [Required] to email

I am not sure how will I work on the keys with all the white space and the [] brackets.

Marked As Solved

Eiji

Eiji

Here is a complete code:

defmodule Example do
  # First of all we call map on our keyword
  def sample(keyword) when is_list(keyword), do: Enum.map(keyword, &rename/1)

  # When key is ok atom and value is a map call rename function
  defp rename({key = :ok, map}) when is_map(map), do: {key, rename(map)}

  # Rename for maps is using for comprehension changing only key and keeping value as is
  defp rename(map) when is_map(map) do
    for {key, value} <- map, into: %{}, do: {rename(key), value}
  end

  # Rename for binary is removing trailing string and calling rename_key
  defp rename(binary) when is_binary(binary) do
    binary |> String.trim_trailing(" [Required]") |> rename_key()
  end

  # A simple pattern-match in rename_key for a special email case
  defp rename_key("Email Address"), do: "email"

  # rename_key for any other string
  defp rename_key(key) when is_binary(key) do
    key |> String.replace(" ", "") |> Macro.underscore()
  end
end

expected_output = [
  ok: %{
    "email" => "fblue@mikasa.com",
    "first_name" => "Blue",
    "last_name" => "First"
  },
  ok: %{
    "email" => "sred@mikasa.com",
    "first_name" => "Red",
    "last_name" => "Second"
  },
  ok: %{
    "email" => "tyellow@mikasa.com",
    "first_name" => "Yellow",
    "last_name" => "Third"
  }
]

input = [
  ok: %{
    "Email Address [Required]" => "fblue@mikasa.com",
    "First Name [Required]" => "Blue",
    "Last Name [Required]" => "First"
  },
  ok: %{
    "Email Address [Required]" => "sred@mikasa.com",
    "First Name [Required]" => "Red",
    "Last Name [Required]" => "Second"
  },
  ok: %{
    "Email Address [Required]" => "tyellow@mikasa.com",
    "First Name [Required]" => "Yellow",
    "Last Name [Required]" => "Third"
  }
]

result = Example.sample(input)
IO.puts(result == expected_output)
# true

Helpful resources:

  1. Kernel.is_list/1
  2. Kernel.is_map/1
  3. Enum.map/2
  4. Kernel.SpecialForms.for/1
  5. String.replace/4
  6. String.trim_trailing/2
  7. Macro.underscore/1
  8. Patterns and Guards

Also Liked

al2o3cr

al2o3cr

The simplest way to accomplish what you’ve written is to look up replacement keys in a supplied map. For instance:

defmodule KeyRenamer do
  @key_replacements %{
    "First Name [Required]" => "first_name",
    "Last Name [Required]" => "last_name",
    "Email Address [Required]" => "email"
  }

  def rename_keys(map) do
    Map.new(map, fn k, v ->
      new_key = Map.get(@key_replacements, k, k)
      {new_key, v}
    end
  end
end

An alternative approach would be to fix the code that’s generating these keys - for instance, if it’s extracting a value from an HTML label maybe it should be using the input's name or something instead…

blackham

blackham

I don’t mind being that guy that comments on OLD threads. I ran into a sexy way to rename some keys (or all if you want). I tried googling for it later and couldn’t find it. Google just keep sending me back to this thread. I eventually found the solution in some old code. So, I’m going to dump this solution here so next time I’ll find it faster. (and maybe it will help someone else)

To rename SOME of the keys:

bad_data = %{
  "lat" => 12.43244,
  long: -5.342,
  name: "something",
  age: 91
}

good_data = Map.new(bad_data, fn
  {"lat", lat} -> {"latitude", lat}
  {:long, long} -> {:longitude, long}
  anything -> anything
end)

Results:

%{
:age => 91,
:longitude => -5.342,
:name => "something",
"latitude" => 12.43244
}

I mixed :keys and “keys” in the example to show it works with both.

good_data should now have the keys latitude, longitude, name, age. It might be cool if Hexdoc had a section showing some common uses that aren’t functions, but indexed like functions. Example “rename_key()” Don’t need the function because you can easily do it like (copy and paste example above)

sabiwara

sabiwara

Elixir Core Team

If the keys are known and static, and you don’t need to make this logic reusable, you could also use plain pattern-matching:

  def rename_keys(%{
    "First Name [Required]" => first_name,
    "Last Name [Required]" => last_name,
    "Email Address [Required]" => email
  }) do
    %{first_name: first_name, last_name: last_name, email: email}
  end
kokolegorille

kokolegorille

You might remove [Required] with String.replace + trim. You might even transform “LastName” to “last_name” with Macro.underscore.

But how do You want him to translate “Email Address” to “email”?

Unless You use some custom rules…

msimonborg

msimonborg

for "Last Name [Required]""last_name"

key |> String.trim(" [Required]") |> String.downcase() |> String.replace(" ", "_")

for "Email Address [Required]""email", you might just pattern match on the special case in a multiple function clause

defp rename_key({"Email Address [Required]", val}), do: {"email", val}
defp rename_key({key, val}) do
  # operate on the key
  {new_key, val}
end

Where Next?

Popular in Questions Top

sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

We're in Beta

About us Mission Statement