Does Elixir guarantee that element sequence of an existing Map's keys() and values() is one-to-one corresponding relations?

I have a map in Elixir:

iex(59)> m = %{"a"=>1, "b"=>2, "c" => 3}
iex(60)> Map.keys(m)                    
["a", "b", "c"]
iex(61)> Map.values(m)
[1, 2, 3]

Are two list [“a”, “b”, “c”] and [1, 2, 3] always one-to-one corresponding relations (I know keys() order isn’t guaranteed)? e.g. keys() return [“b”, “a”, “c”], does values() return [2, 1, 3]?

Hey @heihuhu310 welcome! Map.values ultimately calls the erlang :maps.values which is documented here Erlang -- maps and it says

Returns a complete list of values, in arbitrary order, contained in map Map.

I do not think you can rely on the order, even if it always works today.

8 Likes

I got it, thanks for your help~

You can do things in one go however, which ensures order matches between the two lists:

iex(1)> Enum.unzip(%{"a"=>1, "b"=>2, "c" => 3})
{["a", "b", "c"], [1, 2, 3]}
9 Likes

As a sidenote, If you want to use an ordered map which has the same interface of Map module, check out OrderedMap which is implemented by Jonathan Storm.

1 Like

Now you’ve got me trying to understand why keys and values are currently synced.

I found the definitions in erl_map.c but they seem to use a “yielding c fun” generated at compile-time which has defeated me. At least they both use the same erts_ycf_trap_driver function, which may result in the same enumeration order in both cases.

1 Like

I haven’t looked at the source, but it’s probably different implementations based on map size. Try making a map with an arbitrarily large number of keys (>200) and I’m sure it’ll no longer be ordered

Edit: this is a pretty neat post going in depth Breaking Erlang Maps #1. First part in a series of an Erlang… | by Jesper L. Andersen | Medium

2 Likes

Large maps start at > 32 keys.

https://www.erlang.org/doc/efficiency_guide/advanced.html#memory

4 Likes

Yup thanks for the correction, I saw that in the link I edited in but didn’t change my initial guess :stuck_out_tongue:

No, the keys and values are synced even for maps with more than 32 values, that’s why I got curious. :slight_smile:

That’s really I want.

To clarify, the order from Map.keys and Map.values will match, but they are arbitrary.

2 Likes

OK, but how is that?

this is the definition of Map.values/1

defdelegate values(map), to: :maps

so :maps.values is called which “Returns a complete list of values, in arbitrary order.”

defdelegate keys(map), to: :maps

:maps.keys “Returns a complete list of keys, in any order, which resides within Map.”

It is arbitrary because the map order is arbitrary, not because it is arbitrary to its own keys.

2 Likes