Чи є еквівалент функції Zip в Clojure Core або Contrib?


130

У Clojure я хочу об'єднати два списки, щоб дати список пар,

> (zip '(1 2 3) '(4 5 6))  
((1 4) (2 5) (3 6))

У Haskell або Ruby функція називається zip . Реалізувати це не складно, але я хотів переконатися, що я не пропустив функцію в Core або Contrib.

У Core є простір імен zip , але він описується як надання доступу до функціональної техніки Zipper, яка, здається, не є такою, якою я займаюся.

Чи існує еквівалентна функція для комбінування 2 або більше списків таким чином у Core?

Якщо цього немає, чи не тому, що існує ідіоматичний підхід, який робить цю функцію непотрібною?


У zipбібліотеці Tupelo є функція: cloojure.github.io/doc/tupelo/tupelo.core.html#var-zip
Алан Томпсон

Відповіді:


220
(map vector '(1 2 3) '(4 5 6))

робить те, що ти хочеш:

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

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

На відміну від цього, Clojure та інші Lisps мають хорошу підтримку функцій змінної арності; mapє однією з них і може використовуватися для "тупання" способом, подібним до Хаскелла

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

Ідіоматичний спосіб побудови "кортежу" в Clojure - це побудова короткого вектора, як показано вище.

(Тільки для повноти зауважте, що Haskell з деякими базовими розширеннями дозволяє використовувати функції змінної арності, хоча їх використання вимагає хорошого розуміння мови, однак, а ванільний Haskell 98, ймовірно, зовсім не підтримує їх, тому фіксовані функції arity є кращими для стандартної бібліотеки.)


8
Зауважте, що це поводиться інакше, ніж zipколи колекції не однакової довжини. Ruby продовжить обробку та поставить nilдля коротшої колекції, тоді як Clojure припинить обробку, коли одна з колекцій буде вичерпана.
Нейт У.

@NateW. Це добре зазначити, дякую. У Хаскелл в цьому відношенні zipповодиться як Клуджур map.
Michał Marczyk

1
Чи можу я попросити довідку щодо функцій Haskell із змінною арті?
Теодор

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


11

щоб дати вам саме те, що ви хотіли, відображення listдвох списків надасть вам список списків, як у вашому прикладі. Я думаю, що багато клоурійці схильні використовувати для цього вектори, хоча це буде працювати з чим завгодно. і входи не повинні бути однотипними. 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))

1
Я думаю, ви маєте на увазі хеш-карту та хеш-набір замість карти та встановлення.
cgrand

3

Вбудованим способом буде просто функція "переплетення":

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

6
для досягнення мети ОП слід додати(partition 2 (interleave [1 2 3 4][5 6 7 8]))
скуро

так - Схоже, я не надто пильно подивився на бажаний вихід ОП.
lsh

-1

Існує функція, яка називається zipmap, яка може мати подібний ефект (zipmap (1 2 3)(4 5 6)) Вихід є таким, як падає: {3 6, 2 5, 1 4}


zipmap повертає вам карту, яка не гарантує замовлення
Ілля Шинкаренко

-2

# (застосувати список карт%) транспортує матрицю так само, як функцію zip * Python. Як визначення макросу:

user => (defmacro py-zip [lst] `(застосувати список карт ~ lst))

# 'користувач / py-zip

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


Як це краще, ніж просто використовувати "карту"? І який сенс макросу тут?
Дейв Ньютон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.