Изучение Clojure, часть VI

В предыдущем посте мы уже узнали, как использовать списки и о важности этой структуры данных в Clojure. Теперь мы познакомимся с другой важной структурой данных: Вектор.

Что такое векторы?

Векторы, как и списки, – это неизменяемые постоянные коллекции данных, которые могут содержать любое значение. Их можно создавать с помощью функции vec, передавая коллекцию значений или передавая значения непосредственно между квадратными скобками.

;; (vec collection)
(vec '("Red" "Green" "Blue"))
;; returns => ["Red" "Green" "Blue"]

["Gold" "Silver" "Crystal"]
;; returns => ["Gold" "Silver" "Crystal"]
Вход в полноэкранный режим Выход из полноэкранного режима

Векторы и списки

И векторы, и списки – это коллекции данных, но они сильно отличаются друг от друга тем, как каждый из них работает. Первое основное различие, которое вы, вероятно, заметили между ними, заключается в том, что списки записываются с использованием круглых скобок, а векторы – с использованием квадратных скобок.

'("List" 1 2 3)
;; returns => ("List" 1 2 3)

["Vector" 1 2 3]
;; returns => ["Vector" 1 2 3]
Вход в полноэкранный режим Выход из полноэкранного режима

На первый взгляд кажется, что они делают одно и то же, но структура данных, лежащая в основе этих коллекций, различна и имеет много отличий в практическом использовании.

(class '("List" 1 2 3))
;; returns => clojure.lang.PersistentList

["Vector" 1 2 3]
;; returns => clojure.lang.PersistentVector
Вход в полноэкранный режим Выход из полноэкранного режима

В то время как списки, как нам кажется, представляют собой непрерывные значения в памяти, которые хранят значение и ссылку на следующее значение, векторы – это непрерывные значения в памяти, элементы которых проиндексированы и к ним можно получить быстрый доступ по их индексной позиции с помощью функции nth.

;; (nth collection index)

(nth ["Charmander" "Pikachu" "Buterfree"] 0)
;; returns => "Charmander"

(nth ["Charmander" "Pikachu" "Buterfree"] 2)
;; returns => "Buterfree"
Вход в полноэкранный режим Выход из полноэкранного режима

Изображение: “Представление векторов”, созданное автором, является материалом с авторским левом под нелицензией.

Добавление значений

Еще одно большое различие между ними – это когда мы используем функцию conj для добавления элемента в коллекцию, потому что эта функция быстрее добавит элемент в коллекцию:

  • В списках быстрее добавить новый элемент в начало, так как для этого не нужно проходить весь список, чтобы добавить его на другую позицию.
  • В векторах элемент добавляется в последнюю позицию, так как функция просто получает последний индекс и добавляет его после.

Изображение: “Conj vector vs list”, созданное автором, является объектом авторского права по нелицензионной лицензии.

Мы можем убедиться в этом на некоторых примерах:

(conj  '("Charmander" "Pikachu" "Buterfree") "Zubat")
;; returns => ("Zubat" "Charmander" "Pikachu" "Buterfree")

(conj  ["Charmander" "Pikachu" "Buterfree"] "Zubat")
;; returns => ["Charmander" "Pikachu" "Buterfree" "Zubat"]
Вход в полноэкранный режим Выход из полноэкранного режима

Векторы и списки

Мы можем использовать nth для эффективного доступа к значению по его позиции, но мы также можем использовать любые функции, которые мы уже видели в списках. Их можно использовать для итерации по вектору, как мы это делаем со списками и другими коллекциями.

first

Функция first возвращает элемент в начале вектора.

(first ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Brock"
Вход в полноэкранный режим Выход из полноэкранного режима

second

Функция second возвращает второй элемент вектора.

(second ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Misty"
Войти в полноэкранный режим Выйти из полноэкранного режима

last

Функция last возвращает элемент в конце вектора.

(last ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => "Erika"
Войти в полноэкранный режим Выйти из полноэкранного режима

rest

Функции rest возвращают вектор в виде списка без первого элемента.

(rest ["Brock" "Misty" "Lt. Surge" "Erika"])
;; returns => ("Misty" "Lt. Surge" "Erika")
Войти в полноэкранный режим Выйти из полноэкранного режима

Когда следует использовать списки вместо векторов?

Если вы собираетесь постоянно добавлять и извлекать значения в начале или в конце коллекции, то список будет намного эффективнее вектора.

С другой стороны, если вам нужно добавлять и извлекать значения в середине или в индексированных позициях, то вектор будет намного эффективнее списка.

Вы должны учитывать это при выборе, какой из них вы будете использовать, так как в большинстве случаев векторы используются чаще, чем списки.

Увидимся в следующей части!

Наличие двух разных коллекций, которые выглядят так похоже, а работают так по-разному, может быть немного запутанным на начальном этапе, особенно если вы не знаете, как создаются эти структуры данных, но не волнуйтесь, это станет естественным, когда вы привыкнете к Clojure.

Оцените статью
Procodings.ru
Добавить комментарий