A map is a collection of key/value pairs. A map literal looks like this:
| %{ key => value, key => value } |
Here are some maps:
| iex> states = %{ "AL" => "Alabama", "WI" => "Wisconsin" } |
| %{"AL" => "Alabama", "WI" => "Wisconsin"} |
| |
| iex> responses = %{ { :error, :enoent } => :fatal, { :error, :busy } => :retry } |
| %{{:error, :busy} => :retry, {:error, :enoent} => :fatal} |
| |
| iex> colors = %{ :red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff } |
| %{blue: 255, green: 65280, red: 16711680} |
In the first case the keys are strings, in the second they’re tuples, and in the third they’re atoms. Although typically all the keys in a map are the same type, that isn’t required.
| iex> %{ "one" => 1, :two => 2, {1,1,1} => 3 } |
| %{:two => 2, {1, 1, 1} => 3, "one" => 1} |
If the key is an atom, you can use the same shortcut that you use with keyword lists:
| iex> colors = %{ red: 0xff0000, green: 0x00ff00, blue: 0x0000ff } |
| %{blue: 255, green: 65280, red: 16711680} |
You can also use expressions for the keys in map literals:
| iex> name = "José Valim" |
| "José Valim" |
| iex> %{ String.downcase(name) => name } |
| %{"josé valim" => "José Valim"} |
Why do we have both maps and keyword lists? Maps allow only one entry for a particular key, whereas keyword lists allow the key to be repeated. Maps are efficient (particularly as they grow), and they can be used in Elixir’s pattern matching, which we discuss in later chapters.
In general, use keyword lists for things such as command-line parameters and passing around options, and use maps when you want an associative array.
You extract values from a map using the key. The square-bracket syntax works with all maps:
| iex> states = %{ "AL" => "Alabama", "WI" => "Wisconsin" } |
| %{"AL" => "Alabama", "WI" => "Wisconsin"} |
| iex> states["AL"] |
| "Alabama" |
| iex> states["TX"] |
| nil |
| |
| iex> response_types = %{ { :error, :enoent } => :fatal, |
| ...> { :error, :busy } => :retry } |
| %{{:error, :busy} => :retry, {:error, :enoent} => :fatal} |
| iex> response_types[{:error,:busy}] |
| :retry |
If the keys are atoms, you can also use a dot notation:
| iex> colors = %{ red: 0xff0000, green: 0x00ff00, blue: 0x0000ff } |
| %{blue: 255, green: 65280, red: 16711680} |
| iex> colors[:red] |
| 16711680 |
| iex> colors.green |
| 65280 |
You’ll get a KeyError if there’s no matching key when you use the dot notation.