Существует ли эквивалент функции Zip в Clojure Core или Contrib?
В Clojure, я хочу объединить два списка, чтобы дать список пар,
> (zip '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
В Haskell или Ruby функция называется zip. Реализация этого не составляет труда, но я хотел удостовериться, что у меня не было функции в Core или Contrib.
В Core существует zip пространство имен, но оно описанный в качестве обеспечения доступа к функциональному методу Zipper, который, похоже, не является тем, чем я занимаюсь.
Есть ли эквивалентная функция для объединения двух или более списков, таким образом, в Core?
Если этого не происходит, это потому, что существует идиоматический подход, который делает ненужную функцию?
Ответы
Ответ 1
(map vector '(1 2 3) '(4 5 6))
делает то, что вы хотите:
=> ([1 4] [2 5] [3 6])
Haskell нуждается в наборе функций zipWith
(zipWith3
, zipWith4
,...), потому что все они должны быть определенного типа; в частности, должно быть исправлено количество входных списков, которые они принимают. (Семейство zip
, zip2
, zip3
,... можно рассматривать как специализацию семейства zipWith
для общего использования tupling).
Напротив, Clojure и другие Lisps имеют хорошую поддержку функций переменной arity; map
является одним из них и может использоваться для "tupling" способом, подобным Haskell's
zipWith (\x y -> (x, y))
Идиоматическим способом построения "кортежа" в Clojure является построение короткого вектора, как показано выше.
(Просто для полноты, обратите внимание, что Haskell с некоторыми базовыми расширениями допускает переменные функции arity, поэтому их использование требует хорошего понимания языка, и ванильный Haskell 98, вероятно, вообще не поддерживает их, таким образом фиксированная арность функции предпочтительны для стандартной библиотеки.)
Ответ 2
(map vector [1 2 3] [4 5 6])
Ответ 3
(partition 2 (interleave '(1 2 3) '(4 5 6)))
=> ((1 4) (2 5) (3 6))
или в целом
(defn zip [& colls]
(partition (count colls) (apply interleave colls)))
(zip '( 1 2 3) '(4 5 6)) ;=> ((1 4) (2 5) (3 6))
(zip '( 1 2 3) '(4 5 6) '(2 4 8)) ;=> ((1 4 2) (2 5 4) (3 6 8))
Ответ 4
чтобы дать вам именно то, что вы хотели, сопоставление list
по двум спискам даст вам список списков, как в вашем примере. Я думаю, что многие клоурианцы будут использовать векторы для этого, хотя они будут работать с чем угодно. и входы не должны быть одного типа. map создает seqs из них, а затем отображает seqs, поэтому любой вводный ввод будет работать нормально.
(map list '(1 2 3) '(4 5 6))
(map list [1 2 3] '(4 5 6))
(map hash-map '(1 2 3) '(4 5 6))
(map hash-set '(1 2 3) '(4 5 6))
Ответ 5
Встроенный способ был бы просто функцией "чередование":
(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]
Ответ 6
# (применить список карт%) переносит матрицу так же, как функция zip * Python. Как определение макроса:
user = > (defmacro py-zip [lst] `(применить список карт ~ lst))
# 'пользователь/ая-молния
user = > (py-zip '((1 2 3 4) (9 9 9 9) (5 6 7 8)))
((1 9 5) (2 9 6) (3 9 7) (4 9 8))
user = > (py-zip '((1 9 5) (2 9 6) (3 9 7) (4 9 8)))
((1 2 3 4) (9 9 9 9) (5 6 7 8))
Ответ 7
Существует функция, называемая zipmap, которая может иметь аналогичный эффект, (zipmap (1 2 3)
(4 5 6))
Вывод как fllows: {3 6, 2 5, 1 4}