Я часто нахожусь в ленивом списке, когда хочу вектор, и наоборот. Кроме того, иногда у меня есть вектор карт, когда мне действительно нужен набор карт. Есть ли вспомогательные функции, которые помогут мне преобразовать эти типы?
В 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}}