Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is ordering of keys and values preserved in Elixir when you operate on a map?

Tags:

Suppose I have a map in Elixir:

m = %{"a"=>1, "b"=>2, "c" => 3} 

If I call Map.values(m), am I guaranteed that the return value will always be [1, 2, 3] in that order and not say, [3, 1, 2]?

This is one thing I am not clear on from the docs. After some preliminary testing, I think it is.

like image 489
Nona Avatar asked Nov 03 '16 00:11

Nona


People also ask

Are elixir maps ordered?

Maps' keys do not follow any ordering.

Is map key elixir?

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).

What are the key-value data structures in Elixir?

Maps are the "go to" key-value data structure in Elixir. Maps can be created with the % {} syntax, and key-value pairs can be expressed as key => value: 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).

What happens if map doesn't contain key in Elixir?

Note that map.key will raise a KeyError if the map doesn't contain the key :key, compared to map [:key], that would return nil. Note: do not add parens when accessing fields, such as in data.key () . If parenthesis are used, Elixir will expect data to be an atom representing a module and attempt to call the function key/0 in it.

What is the Order of key values in a map?

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). Maps do not impose any restriction on the key type: anything can be a key in a map. As a key-value structure, maps do not allow duplicated keys.

What is keyword list in Elixir?

Keyword list is a list of tuples, where the first tuple element is an atom. In Elixir it is used as an optional list of function parameters. Many Elixir libraries stick to that convention. We have two options to define a Keyword list and two options to use it as a function parameter.


2 Answers

The implementation of Maps in Elixir and Erlang has some confusing properties. For small values of entries it is a sorted key list, and thus appears to have the properties you see in simple experiments.

Above a certain number of entries (32 I think), the implementation switches to Hash Array Mapped Trie and all the properties you see disappear. You can not depend on the order of either the keys or the values of a map in the general case. See

https://en.wikipedia.org/wiki/Hash_array_mapped_trie

for an explaination of the underlying structure of Map.

 iex(7)> 1..33 |> Enum.reduce(%{}, fn(x, acc) -> Map.put(acc,x,x) end ) %{11 => 11, 26 => 26, 15 => 15, 20 => 20, 17 => 17, 25 => 25, 13 => 13, 8 => 8,   7 => 7, 1 => 1, 32 => 32, 3 => 3, 6 => 6, 2 => 2, 33 => 33, 10 => 10, 9 => 9,   19 => 19, 14 => 14, 5 => 5, 18 => 18, 31 => 31, 22 => 22, 29 => 29, 21 => 21,   27 => 27, 24 => 24, 30 => 30, 23 => 23, 28 => 28, 16 => 16, 4 => 4, 12 => 12}   iex(8)> Map.keys(v(7)) [11, 26, 15, 20, 17, 25, 13, 8, 7, 1, 32, 3, 6, 2, 33, 10, 9, 19, 14, 5, 18, 31,  22, 29, 21, 27, 24, 30, 23, 28, 16, 4, 12]   iex(9)> Map.values(v(7)) [11, 26, 15, 20, 17, 25, 13, 8, 7, 1, 32, 3, 6, 2, 33, 10, 9, 19, 14, 5, 18, 31,  22, 29, 21, 27, 24, 30, 23, 28, 16, 4, 12] 
like image 107
Fred the Magic Wonder Dog Avatar answered Sep 22 '22 19:09

Fred the Magic Wonder Dog


From the Elixir website:

Compared to keyword lists, we can already see two differences:

  • Maps allow any value as a key.
  • Maps’ keys do not follow any ordering.

While the Elixir website clearly states that Maps do not follow any ordering, they do follow a specific order after they've created (but do not preserve their order of creation). It seems that the Maps are organized alphabetically according to their keys (but I have nothing to back this up except a few experiments in IEx):

map = %{c: 3, a: 1, b: 2}  map                       # => %{a: 1, b: 2, c: 3} Map.keys(map)             # => [:a, :b, :c] Map.values(map)           # => [1, 2, 3] 

Since you asked about preserving the original order, The answer is NO.


Better Option: Keyword Lists

A better alternative would be to use Keyword lists (which are a linked-list of two element tuples underneath). Because of this, the order of their creation is maintained:

kw = [c: 3, a: 1, b: 2]  kw                       # => [c: 3, a: 1, b: 2] Keyword.keys(kw)         # => [:c, :a, :b] Keyword.values(kw)       # => [3, 1, 2] 
like image 27
Sheharyar Avatar answered Sep 22 '22 19:09

Sheharyar