Списки, векторы, map и множества
Знакомимся с четырьмя основными коллекциями Clojure и учимся выбирать подходящую.
Коллекция в Clojure — неизменяемая структура данных; любая «модификация» возвращает новую коллекцию, оставляя исходную нетронутой.
Четыре базовые коллекции
| Тип | Запись | Когда использовать |
| Список (list) | '(1 2 3) | код, последовательная обработка с начала |
| Вектор (vector) | [1 2 3] | индексированный доступ, как массив |
| Отображение (map) | {:a 1 :b 2} | пары ключ→значение, записи |
| Множество (set) | #{1 2 3} | уникальные элементы, проверка вхождения |
Векторы
Вектор — самая частая коллекция, аналог массива/списка из других языков, но с быстрым доступом по индексу:
(def числа [10 20 30])
(nth числа 0) ; => 10 (элемент по индексу)
(count числа) ; => 3
(conj числа 40) ; => [10 20 30 40] (новый вектор, исходный цел)
числа ; => [10 20 30] (не изменился!)Вывод:
10 3 [10 20 30 40] [10 20 30]
Отображения (map)
Map хранит пары «ключ → значение» и заменяет в Clojure роль объектов:
(def книга {:название "Clojure" :год 2007})
(get книга :год) ; => 2007
(:название книга) ; => "Clojure"
(assoc книга :автор "Hickey") ; => новый map с автором
(keys книга) ; => (:название :год)Вывод:
2007
"Clojure"
{:название "Clojure", :год 2007, :автор "Hickey"}
(:название :год)Множества
Множество хранит только уникальные элементы и быстро отвечает, есть ли что-то внутри:
(def цвета #{:красный :зелёный})
(contains? цвета :красный) ; => true
(conj цвета :красный) ; => #{:красный :зелёный} (дубликат игнорируется)
(conj цвета :синий) ; => #{:красный :зелёный :синий}Вывод:
true
#{:красный :зелёный}
#{:красный :зелёный :синий}Как работает под капотом
Списки реализованы как односвязные: дешево добавлять в начало, дорого — обращаться по индексу. Векторы — как деревья с большим ветвлением, поэтому доступ по индексу почти константный. Map и set построены на хэш-деревьях. Важно: все они неизменяемы, и любая операция вроде conj или assoc создаёт новую версию, не трогая старую.
Частые ошибки
- Ждать, что
conjизменит коллекцию. Он возвращает новую; старая остаётся прежней. Сохраняйте результат. - Путать, куда
conjдобавляет. В вектор — в конец, в список — в начало. - Использовать список там, где нужен индексный доступ. Для этого есть вектор.
Итоги
- Четыре коллекции: список, вектор, map, множество — каждая для своей задачи.
- Все коллекции неизменяемы: операции возвращают новую структуру.
- Вектор — для индексного доступа, map — для записей, set — для уникальности.
- Keyword отлично подходит на роль ключей в map.
Проверьте себя
1. Как записывается вектор в Clojure?
A(1 2 3)
B[1 2 3]
C{1 2 3}
D#{1 2 3}
2. Что вернёт (conj [1 2 3] 4)?
A[1 2 3] (без изменений)
B[4 1 2 3]
C[1 2 3 4]
DОшибку, вектор изменять нельзя
3. Какая коллекция хранит только уникальные элементы?
AСписок
BВектор
CMap
DМножество (set)