Dania_es
Dania_es

Reputation: 1036

How to put key value pair into map with variable key name

I'm trying to end up with a single map containing many different preferences, it should look like this:

%{some_preference_name:%{foo:"bar"},another_preference_name:%{foo:"bar"}}

I have a list of preference maps from the database, and I need to get through them and set the "preference" field as the key with the various values as the values map.

I tried to do this with Enum.reduce and Enum,map, but I can't get the list right.

Enum.map(preferences, fn(data)->
  Map.put(%{}, data.preference,
   %{
     foo: data.foo
    }
  )
end)

returns:

[{some_preference_name:%{foo:"bar"}},{another_preference_name:%{foo:"bar"}}]

then:

Enum.reduce(preferences, fn(acc, data)->
  Map.put(acc, data.preference,
   %{
     foo: data.foo
    }
  )
end)

returns:

%{some_preference_name:%{foo:"bar"},preference: "another_preference_name",foo:"bar"}

It gets the first one right, but not the rest. I understand that as of Erlang R17, the only way I will be able to add a variable key name is with Map.put/3.

Upvotes: 9

Views: 14637

Answers (3)

sobolevn
sobolevn

Reputation: 18090

You can now (since Elixir 1.2.0) do it without any hacks. This is listed in the language improvements section in the changes overview.

That is how to do it:

iex> key = :hello
iex> value = "world"
iex> %{key => value}
%{:hello => "world"}

And if you want to pattern match an existing variable - use ^ operator:

iex> key = :hello
iex> %{^key => value} = %{:hello => "another world"}
iex> value
"another world"

Upvotes: 15

Arkar Aung
Arkar Aung

Reputation: 3584

Try to use hd() and tl() with recursion to get list item instead of Enum.map and Enum.reduce .

def get_preference() do
    preferences = [%{:preference => "some_preference_name", :foo => "bar"}, %{:preference => "another_preference_name", :foo => "rab"}]
    convert(preferences, %{})
end

def convert([], map) do
    map
end

def convert([head|tail], map) do
    map = Map.put(map, head.preference, %{foo: head.foo})
    convert(tail, map)
end

Hope it will be useful for you.

Upvotes: 0

José Valim
José Valim

Reputation: 51439

Your code is almost correct, you have just swapped the arguments order in the reduce function:

Enum.reduce(preferences, fn(data, acc)->
  Map.put(acc, data.preference, %{foo: data.foo})
end)

Upvotes: 16

Related Questions