Есть ли эквивалент для функции Zip в Clojure Core или Contrib? - PullRequest
115 голосов
/ 07 апреля 2010

В 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 ]

200 голосов
/ 07 апреля 2010
(map vector '(1 2 3) '(4 5 6))

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

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

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

Напротив, Clojure и другие Лиспы имеют хорошую поддержку функций переменной арности; map является одним из них и может использоваться для «кортежа» способом, аналогичным

для Haskell.
zipWith (\x y -> (x, y))

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

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

15 голосов
/ 23 июля 2013
(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))
12 голосов
/ 07 апреля 2010
(map vector [1 2 3] [4 5 6])
10 голосов
/ 07 апреля 2010

, чтобы дать вам именно то, что вы хотели, отображение 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))
3 голосов
/ 15 августа 2012

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

(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]
0 голосов
/ 07 января 2015

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

0 голосов
/ 30 мая 2014

# (применить список карт%) транспонирует матрицу так же, как функция 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))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...