Есть ли эквивалент для функции 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, которая, похоже, не является тем, чем я занимаюсь.

Есть ли эквивалентная функция для объединения 2 или более списков, таким образом, в Core?

Если нет, это потому, что существует идиоматический подход, который делает функцию ненужной?

7 ответов

Решение
(map vector '(1 2 3) '(4 5 6))

делает то, что вы хотите:

=> ([1 4] [2 5] [3 6])

Хаскеллу нужна коллекция zipWith (zipWith3, zipWith4,...) функции, потому что все они должны быть определенного типа; в частности, число входных списков, которые они принимают, должно быть фиксированным. (The zip, zip2, zip3... семью можно рассматривать как специализацию zipWith семья для общего случая использования tupling).

В отличие от этого, Clojure и другие Лиспы имеют хорошую поддержку функций переменной арности; map является одним из них и может быть использован для "кортежа" способом, аналогичным Haskell's

zipWith (\x y -> (x, y))

Идиоматический способ построения "кортежа" в Clojure - это создание короткого вектора, как показано выше.

(Просто для полноты обратите внимание, что Haskell с некоторыми базовыми расширениями допускает функции переменной arity; хотя для их использования требуется хорошее понимание языка, и ванильный Haskell 98, вероятно, вообще их не поддерживает, поэтому предпочтительны фиксированные функции arity. для стандартной библиотеки.)

(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))
(map vector [1 2 3] [4 5 6])

Чтобы дать вам именно то, что вы хотели, картирование list через два списка вы получите список списков, как в вашем примере. Я думаю, что многие Clojurians будут склонны использовать векторы для этого, хотя это будет работать с чем угодно. и входы не должны быть одного типа. map создает из них seqs, а затем отображает seqs так, что любой ввод seq'able будет работать нормально.

(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))

Встроенным способом будет просто функция interleave:

(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]

#(применить список карт%) транспонирует матрицу так же, как функция Python zip*. Как определение макроса:

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))

Существует функция с именем zipmap, которая может иметь аналогичный эффект, (zipmap (1 2 3)(4 5 6)) Выходной сигнал выглядит следующим образом: {3 6, 2 5, 1 4}

Другие вопросы по тегам