Eric Budd
Eric Budd

Reputation: 531

Elixir: How to convert a keyword list to a map?

I have a keyword list of Ecto changeset errors I'd like to convert to a map so that the Poison JSON parser can correctly output a list of validation errors in the JSON format.

I get a list of errors as follows:

[:topic_id, "can't be blank", :created_by, "can't be blank"]

...and I'd like to get a map of errors like so:

%{topic_id: "can't be blank", created_by: "can't be blank"}

Alternatively, if I could convert it to a list of strings, I could use that as well.

What is the best way to accomplish either of these tasks?

Upvotes: 42

Views: 23236

Answers (4)

Boris Barroso
Boris Barroso

Reputation: 1812

Another solution:

[:topic_id, "can't be blank", :created_by, "can't be blank"]
|> Enum.chunk(2) 
|> Enum.into(%{}, &List.to_tuple/1)

Upvotes: 0

Gazler
Gazler

Reputation: 84140

What you have there isn't a keyword list, it is just a list with every odd element representing a key and every even element representing a value.

The difference is:

[:topic_id, "can't be blank", :created_by, "can't be blank"] # List
[topic_id: "can't be blank", created_by: "can't be blank"]   # Keyword List

A keyword list can be turned into a map using Enum.into/2

Enum.into([topic_id: "can't be blank", created_by: "can't be blank"], %{})

Since your data structure is a list, you can convert it using Enum.chunk_every/2 and Enum.reduce/3

[:topic_id, "can't be blank", :created_by, "can't be blank"]
|> Enum.chunk_every(2)
|> Enum.reduce(%{}, fn ([key, val], acc) -> Map.put(acc, key, val) end)

You can read more about Keyword lists at http://elixir-lang.org/getting-started/maps-and-dicts.html

Upvotes: 72

Roman Smirnov
Roman Smirnov

Reputation: 533

Yet another way to do that is by using of list comprehension:

iex> list = [:topic_id, "can't be blank", :created_by, "can't be blank"]
iex> map = for [key, val] <- Enum.chunk(list, 2), into: %{}, do: {key, val}
%{created_by: "can't be blank", topic_id: "can't be blank"}

Besides you can convert your list to keyword list:

iex> klist = for [key, val] <- Enum.chunk(list, 2), do: {key, val}
[topic_id: "can't be blank", created_by: "can't be blank"]

It could be also useful in some cases.

You can read more about this use case at http://elixir-lang.org/getting-started/comprehensions.html#results-other-than-lists

Upvotes: 6

Gjaldon
Gjaldon

Reputation: 5644

Another way to do this is by combining Enum.chunk/2 with Enum.into/3. For example:

[:topic_id, "can't be blank", :created_by, "can't be blank"]
|> Enum.chunk(2)
|> Enum.into(%{}, fn [key, val] -> {key, val} end)

Upvotes: 11

Related Questions