Бесплатный курс по elixir. Зарегистрируйтесь для отслеживания прогресса →

Elixir: Словари

Словарь (Map) хранит пары ключ-значение. Это еще одна динамическая структура данных в которую можно добавлять и удалять элементы.

Словарь создается с помощью конструкции %{key1 => value1, key2 => value2}. Для обращения по ключу используются квадратные скобки:

my_map = %{"a" => 1, "b" => 2}
my_map["a"] # 1
my_map["b"] # 2

Часто в качестве ключей используют атомы:

other_map = %{:a => 1, :b => 2}
other_map[:a] # 1
other_map[:b] # 2

Для ключей атомов (и только в этом случае) можно использовать синтаксический сахар:

other_map = %{a: 1, b: 2}      
other_map.a # 1
other_map.b # 2

Обращение через квадраные скобки и обращение через точку работают по-разному в случае, когда ключ отсутствует в словаре:

other_map[:c] # nil
other_map.c  # ** (KeyError) key :c not found in: %{a: 1, b: 2}

Как видим, в первом случае возвращается значение nil, а во втором случае генерируется исключение.

Функция Map.get работает так же, как обращение через квадратные скобки. Но она позволяет указать дефолтное значение для отсутствующего ключа:

Map.get(other_map, :a) # 1
Map.get(other_map, :c) # nil
Map.get(other_map, :c, 42) # 42

Для добавления нового ключа или для изменения значения существующего ключа используется функция Map.put:

Map.put(other_map, :c, 42) # %{a: 1, b: 2, c: 42}
Map.put(other_map, :a, 42) # %{a: 42, b: 2}

Словарь, как и все остальные значения в Элисир, является иммутабельным. Поэтому функция Map.put возвращает новый словарь, а старый остается неизменным:

new_map = Map.put(other_map, :c, 42)
IO.puts(inspect(new_map)) # => %{a: 1, b: 2, c: 42}
IO.puts(inspect(other_map)) # => %{a: 1, b: 2}

Для изменения значения существующего ключа есть синтаксический сахар:

%{other_map | :a => 42} # %{a: 42, b: 2}
%{other_map | :a => 42 , :b => 43} # %{a: 42, b: 43}

Такой синтаксис удобен тем, что позволяет изменять несколько ключей сразу.

А добавить новый ключ этот синтаксис не позволяет:

%{other_map | :c => 42} # ** (KeyError) key :c not found in: %{a: 1, b: 2}

Для удаления ключа используется функция Map.delete. Она тоже возвращает новый словарь, а старый остается неизменным:

Map.delete(other_map, :a) # %{b: 2}

Задание

Реализовать функцию keys_sum, которая принимает словарь и два ключа, извлекает значения по этим ключам, и возвращает сумму значений. Если ключа в словаре нет, то соответствующее значение не учитывается.

Реализовать функцию keys_product, которая принимает словарь и два ключа, извлекает значения по этим ключам, и возвращает произведение значений. Если ключа в словаре нет, то соответствующее значение не учитывается.

Реализовать функцию copy_key, которая принимает два словаря, ключ, и значение по умолчанию. По ключу нужно извлечь значение из первого словаря и вставить во второй словарь. Если в первом словаре нет такого ключа, то во второй словарь нужно вставить значение по умолчанию. Если во втором словаре уже есть такой ключ, то его значение меняется.

defmodule Solution do

  def keys_sum(map, key1, key2) do
    # TODO реализация
  end

  def keys_product(map, key1, key2) do
    # TODO реализация
  end

  def copy_key(from_map, to_map, key, default_value) do
    # TODO реализация
  end

end

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе