Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List to Keyword List in Elixir

I have a list of results that I pulled in using Ecto. I want to end up with a keyword list that I can then use to populate a <select> inside of Phoenix but I'm unsure how to turn this list into a keyword list like ["1": "Author #1", "2": "Author #2"]

authors = Repo.all(Author)
# How would I create ["1": "Author #1", "2": "Author #2"]
like image 450
Kyle Decot Avatar asked Sep 16 '15 19:09

Kyle Decot


People also ask

What is Elixir keyword list?

12.3) A keyword list is a list that consists exclusively of two-element tuples. The first element of these tuples is known as the key, and it must be an atom. The second element, known as the value, can be any term.

Is Elixir a list?

Lists are a basic data type in Elixir for holding a collection of values. Lists are immutable, meaning they cannot be modified. Any operation that changes a list returns a new list. Lists implement the Enumerable protocol, which allows the use of Enum and Stream module functions.

Is Elixir a map?

12.3) Maps are the "go to" key-value data structure in Elixir. Key-value pairs in a map do not follow any order (that's why the printed map in the example above has a different order than the map that was created).


2 Answers

A keyword list expects atoms as keys. The good news is that you don't need a keyword list to give to select. Here are two approaches:

  1. Do it directly in the query:

    authors = Repo.all from a in Author, select: {a.name, a.id}
    
  2. Do it on the data:

    authors = Repo.all Author
    Enum.map(authors, fn a -> {a.name, a.id} end)
    

The advantage of the first one is that you will load only the data you need from the table.

like image 95
José Valim Avatar answered Oct 22 '22 04:10

José Valim


Select just the author names using Enum.map

authorNames = authors |> Enum.map(fn a-> a.name end)

then use Enum.zip to setup the key value pairs

1..Enum.count(authors ) |> Enum.map(fn x-> to_string(x) end) |> Enum.zip(authorNames)

this will produce soemthing like:

[{"1", "Author #1"}, {"2", "Author #2"}]

If you want it to be a true keyword list you need the first element to be a atom because keyword lists only use atoms as keys

1..Enum.count(authors ) |> Enum.map(fn x-> x |> to_string |> String.to_atom end) |> Enum.zip(authorNames)

which will produce

["1": "Author #1", "2": "Author #2"]

But I've always heard to manage the number of atoms you have carefully and that converting large number of strings to atoms isn't a best practice. Unless you know how many authors your query will return you may need to be careful when converting the key numbers to atoms.

like image 29
Letseatlunch Avatar answered Oct 22 '22 03:10

Letseatlunch