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
, которая принимает два словаря, ключ, и значение по умолчанию. По ключу нужно извлечь значение из первого словаря и вставить во второй словарь. Если в первом словаре нет такого ключа, то во второй словарь нужно вставить значение по умолчанию. Если во втором словаре уже есть такой ключ, то его значение меняется.
map = %{a: 1, b: 2, c: 42}
Solution.keys_sum(map, :a, :b)
# => 3
Solution.keys_sum(map, :a, :c)
# => 43
Solution.keys_sum(map, :c, :b)
# => 44
map = %{one: 1, five: 5, ten: 10}
Solution.keys_product(map, :one, :five)
# => 5
Solution.keys_product(map, :five, :ten)
# => 50
Solution.keys_product(map, :two, :ten)
# => 10
map1 = %{a: 1, b: 2}
map2 = %{c: 3, d: 4}
Solution.copy_key(map1, map2, :a, 42)
# => %{c: 3, d: 4, a: 1}
Solution.copy_key(map1, map2, :b, 42)
# => %{c: 3, d: 4, b: 2}
Solution.copy_key(map2, map1, :d, 42)
# => %{a: 1, b: 2, d: 4}
Solution.copy_key(map2, map1, :e, 42)
# => %{a: 1, b: 2, e: 42}
Упражнение не проходит проверку — что делать? 😶
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя 🤔
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно 🙄
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.