В Clojure есть ли простой способ конвертировать между типами списков?

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

Ответ 1

Не забывайте, что надежный старый into позволяет взять что-либо seq в уме (список, вектор, карту, набор, отсортированную карту) и пустой контейнер, который вы хотите заполнить, и помещает его into it.

(into [] '(1 2 3 4)) ==> [1 2 3 4]         "have a lazy list and want a vector"
(into #{} [1 2 3 4]) ==> #{1 2 3 4}        "have a vector and want a set"
(into {} #{[1 2] [3 4]}) ==> {3 4, 1 2}    "have a set of vectors want a map"
(into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"

into является оберткой вокруг conj, которая является базовой абстракцией для вставки новых записей соответствующим образом в коллекцию на основе типа коллекции. Принцип, который делает этот поток настолько красивым, заключается в том, что Clojure построен на составных абстракциях, в этом случае into поверх conj поверх коллекции и seq.

Вышеприведенные примеры все равно будут хорошо составлены, если получатель будет передан во время выполнения: потому что базовые абстракции (seq и conj) реализованы для всех коллекций (и многих коллекций Java), поэтому более высокие абстракции не нужно беспокоиться о множестве специальных случаев, связанных с данными.

Ответ 2

vec, set и вообще into - ваши друзья легко "конвертируют" в другой тип коллекции.

Как вы хотите преобразовать вектор карт в карту отображений? Вам нужен ключ, можете ли вы использовать использование ввода/ожидаемого вывода образца?

Ответ 3

Для векторов существует функция vec

user=> (vec '(1 2 3))
[1 2 3]

Для ленивых последовательностей существует функция lazy-seq

user=> (lazy-seq [1 2 3])
(1 2 3)

Для преобразования в множества существует функция set

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}

Ответ 4

Еще один ответ для перехода от списка к карте (ради полноты) - от здесь:

(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}

Ответ 5

Чтобы преобразовать вектор в список, вы также можете использовать for, например:

=> (for [i [1 2 3 4]] i)
(1 2 3 4)

Если вы не хотите манипулировать данными, просто используйте seq для вектора:

=> (seq [1 2 3])
(1 2 3)

Ответ 6

Нет необходимости конвертировать вектор в список. Clojure будет обрабатывать вектор, поскольку он будет рассматривать список - как последовательность - когда требуется последовательность. Например,

user=> (cons 0 [1 2 3])
(0 1 2 3)

Если вам нужно убедиться, что вектор обрабатывается как последовательность, оберните его в seq:

user=> (conj [1 2 3] 0) ; treated as a vector
[1 2 3 0]

user=> (conj (seq [1 2 3]) 0) ; treated as a sequence
(0 1 2 3)

Если у вас есть вектор карт и вам нужен набор карт, не имеет значения, что вектор содержит карты. Вы просто конвертируете вектор в набор, как обычно:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}