Apakah ada yang setara untuk fungsi Zip di Clojure Core atau Contrib?

130

Di Clojure, saya ingin menggabungkan dua daftar untuk memberikan daftar pasangan,

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

Di Haskell atau Ruby fungsinya disebut zip . Menerapkannya tidak sulit, tetapi saya ingin memastikan saya tidak kehilangan fungsi di Core atau Contrib.

Ada ruang nama zip di Core, tetapi digambarkan sebagai menyediakan akses ke teknik fungsional Zipper, yang tampaknya tidak seperti apa yang saya cari.

Apakah ada fungsi yang setara untuk menggabungkan 2 daftar atau lebih, dengan cara ini, di Core?

Jika tidak ada, apakah itu karena ada pendekatan idiomatik yang membuat fungsi tidak dibutuhkan?

John Kane
sumber
Ada zipfungsi di perpustakaan Tupelo: cloojure.github.io/doc/tupelo/tupelo.core.html#var-zip
Alan Thompson

Jawaban:

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

melakukan apa yang Anda inginkan:

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

Haskell membutuhkan kumpulan fungsi zipWith( zipWith3,, zipWith4...), karena semuanya harus dari tipe tertentu ; khususnya, jumlah daftar input yang mereka terima perlu diperbaiki. (The zip, zip2, zip3, ... keluarga dapat dianggap sebagai spesialisasi dari zipWithkeluarga untuk kasus penggunaan umum dari tupling).

Sebaliknya, Clojure dan Lisps lainnya memiliki dukungan yang baik untuk fungsi variabel arity; mapadalah salah satunya dan dapat digunakan untuk "tupling" dengan cara yang mirip dengan Haskell

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

Cara idiomatis untuk membangun "tuple" di Clojure adalah dengan membuat vektor pendek, seperti yang ditampilkan di atas.

(Hanya untuk kelengkapan, perhatikan bahwa Haskell dengan beberapa ekstensi dasar memang memungkinkan fungsi variabel arity; menggunakan mereka membutuhkan pemahaman yang baik tentang bahasa, dan vanilla Haskell 98 mungkin tidak mendukung mereka sama sekali, sehingga fungsi arity tetap lebih disukai untuk perpustakaan standar.)

Michał Marczyk
sumber
8
Perhatikan bahwa ini berperilaku berbeda dari zipketika koleksi tidak sama panjangnya. Ruby akan terus memproses dan memasok niluntuk koleksi yang lebih pendek, sedangkan Clojure akan berhenti memproses setelah salah satu koleksi habis.
Nate W.
@NateW. Itu bagus untuk dicatat, terima kasih. Dalam Haskell zipberperilaku seperti Clojure mapdalam hal ini.
Michał Marczyk
1
Bolehkah saya meminta referensi tentang fungsi Haskell variabel arity?
Teodor
22
(partition 2 (interleave '(1 2 3) '(4 5 6))) 
=> ((1 4) (2 5) (3 6))

atau lebih umum

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

untuk memberikan apa yang Anda inginkan, pemetaan listdi kedua daftar akan memberi Anda daftar daftar seperti pada contoh Anda. Saya pikir banyak Clojurians cenderung menggunakan vektor untuk ini meskipun itu akan bekerja dengan apa pun. dan input tidak perlu tipe yang sama. map membuat seqs dari mereka dan kemudian memetakan seqs sehingga input seq'able apa pun akan berfungsi dengan baik.

(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))
Arthur Ulfeldt
sumber
1
Saya pikir maksud Anda hash-peta dan hash-set bukan peta dan set.
cgrand
3

Cara bawaannya hanyalah fungsi 'interleave':

(interleave [1 2 3 4] [5 6 7 8]) => [1 5 2 6 3 7 4 8]
lsh
sumber
6
untuk mencapai tujuan OP, Anda harus menambahkan(partition 2 (interleave [1 2 3 4][5 6 7 8]))
skuro
ya - Tampaknya saya tidak melihat output OP yang diinginkan terlalu dekat.
lsh
-1

Ada fungsi yang disebut zipmap, yang mungkin memiliki efek yang sama, (zipmap (1 2 3)(4 5 6)) Ouput sama seperti aliran: {3 6, 2 5, 1 4}

温 发 琥
sumber
zipmap mengembalikan Anda peta, yang tidak menjamin pesanan
Ilya Shinkarenko
-2

# (terapkan daftar peta%) mentransformasikan matriks seperti fungsi Python zip *. Sebagai definisi makro:

user => (defmacro py-zip [lst] `(terapkan daftar peta ~ lst))

# 'pengguna / 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))

dhr bibberknie
sumber
Bagaimana ini lebih baik daripada hanya menggunakan 'peta'? Dan apa gunanya makro di sini?
Dave Newton