Словарь (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}
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1defmodule Test do
2 use ExUnit.Case
3 import Solution
4
5 test "keys_sum" do
6 map = %{a: 1, b: 2, c: 42}
7 assert keys_sum(map, :a, :b) == 3
8 assert keys_sum(map, :a, :c) == 43
9 assert keys_sum(map, :c, :b) == 44
10 assert keys_sum(map, :a, :a) == 2
11 assert keys_sum(map, :a, :d) == 1
12 assert keys_sum(map, :d, :c) == 42
13 assert keys_sum(map, :d, :e) == 0
14 end
15
16 test "keys_product" do
17 map = %{one: 1, five: 5, ten: 10}
18 assert keys_product(map, :one, :five) == 5
19 assert keys_product(map, :one, :ten) == 10
20 assert keys_product(map, :five, :ten) == 50
21 assert keys_product(map, :five, :five) == 25
22 assert keys_product(map, :five, :two) == 5
23 assert keys_product(map, :two, :ten) == 10
24 assert keys_product(map, :two, :three) == 1
25 end
26
27 test "copy_key" do
28 map1 = %{a: 1, b: 2}
29 map2 = %{c: 3, d: 4}
30 assert copy_key(map1, map2, :a, 42) == %{c: 3, d: 4, a: 1}
31 assert copy_key(map1, map2, :b, 42) == %{c: 3, d: 4, b: 2}
32 assert copy_key(map1, map2, :e, 42) == %{c: 3, d: 4, e: 42}
33 assert copy_key(map1, map2, :c, 42) == %{c: 42, d: 4}
34
35 assert copy_key(map2, map1, :c, 42) == %{a: 1, b: 2, c: 3}
36 assert copy_key(map2, map1, :d, 42) == %{a: 1, b: 2, d: 4}
37 assert copy_key(map2, map1, :e, 42) == %{a: 1, b: 2, e: 42}
38 assert copy_key(map2, map1, :b, 42) == %{a: 1, b: 42}
39 end
40end
41
Решение учителя откроется через: