Существует ли эквивалент функции 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}