Как использовать Map, List, Keyword и в чём их отличия?
В Elixir структуры данных Map, List и Keyword используются для хранения и обработки коллекций значений. Несмотря на некоторые внешние сходства, они имеют различное внутреннее устройство, семантику и сценарии применения.
List
List — это обычный связный список, упорядоченный, допускающий повторяющиеся элементы. Элементы добавляются в начало, а не в конец, что делает prepend-операции ([head | tail]) эффективными.
Создание списка:
list = \[1, 2, 3, 4\]
Доступ и работа:
\[head | tail\] = list
IO.inspect(head) # => 1
IO.inspect(tail) # => \[2, 3, 4\]
Методы:
-
Enum.map/2, Enum.reduce/3, Enum.filter/2 — для обхода и преобразования.
-
hd/1, tl/1 — для доступа к голове и хвосту.
-
[value | list] — быстрая вставка в начало.
-
++, -- — объединение и вычитание списков.
Особенности:
-
Быстрые вставки в начало.
-
Медленный произвольный доступ (т.к. список связный).
-
Списки в Elixir не являются массивами.
Map
Map — это ассоциативный массив (хеш-таблица), хранящий пары ключ–значение. Ключи могут быть любого типа, доступ осуществляется за O(1).
Создание:
map = %{name: "Alice", age: 30}
-
Ключ :name — атом.
-
Значение может быть любым типом.
Доступ и обновление:
map\[:name\] # => "Alice"
map.name # => "Alice", если ключ — атом
updated = Map.put(map, :age, 31)
Методы:
-
Map.get/2, Map.put/3, Map.update/4, Map.delete/2
-
Map.merge/2 — объединение мапов.
-
Map.keys/1, Map.values/1
Особенности:
-
Неупорядоченная структура.
-
Ключи уникальны.
-
Быстрый произвольный доступ.
-
Поддерживает pattern matching по ключам:
%{name: n} = map
Keyword
Keyword — это список кортежей вида [{key, value}], где ключи — только атомы, а значения — любые типы. Он упорядочен, поддерживает дубликаты ключей.
Создание:
kw = \[name: "Alice", age: 30\]
\# То же самое, что: \[{:name, "Alice"}, {:age, 30}\]
Доступ:
Keyword.get(kw, :age) # => 30
kw\[:name\] # => "Alice"
Методы:
-
Keyword.get/2, Keyword.put/3, Keyword.delete/2
-
Keyword.merge/2, Keyword.has_key?/2
-
Keyword.keys/1, Keyword.values/1
Особенности:
-
Упорядоченный.
-
Можно иметь дубликаты ключей: [a: 1, a: 2].
-
Часто используется в опциях (options), передаваемых в функции:
MyModule.func(arg, timeout: 1000, retries: 3)
Сравнение по основным признакам
Признак | List | Map | Keyword |
---|---|---|---|
Упорядоченность | Да | Нет | Да |
--- | --- | --- | --- |
Доступ по индексу | Нет | Да (по ключу) | Да (по ключу-атомy) |
--- | --- | --- | --- |
Тип ключей | Нет | Любые | Только атомы |
--- | --- | --- | --- |
Повтор ключей | Нет | Нет | Да |
--- | --- | --- | --- |
Вставка в начало | Быстрая | Не применимо | Быстрая (как список) |
--- | --- | --- | --- |
Производительность доступа | O(n) | O(1) | O(n) |
--- | --- | --- | --- |
Назначение | Перечисление значений | Ассоциативное хранилище | Опции, аргументы функций |
--- | --- | --- | --- |
Примеры использования
Списки:
Enum.map(\[1, 2, 3\], fn x -> x \* 2 end)
Мапы:
user = %{name: "Bob", admin: true}
Map.put(user, :admin, false)
Ключевые списки:
opts = \[timeout: 5000, retries: 3\]
Keyword.get(opts, :timeout)
Pattern matching:
%{a: x} = %{a: 10, b: 20}
\[x | \_\] = \[1, 2, 3\]
\[{k, v} | \_\] = \[name: "Elixir", lang: "BEAM"\]
Когда использовать:
-
List: когда нужен упорядоченный набор элементов, перебираемый последовательно.
-
Map: когда нужен быстрый доступ по ключу и строгая уникальность ключей.
-
Keyword: когда передаёшь опции в функцию или хочешь сохранить порядок и допускаешь дубли.
Таким образом, List, Map и Keyword в Elixir — это три фундаментальных инструмента для представления данных. Они не заменяют друг друга, а используются в зависимости от конкретной задачи, структуры и требований к производительности или семантике.