มีฟังก์ชัน Zip ที่เทียบเท่าใน Clojure Core หรือ Contrib หรือไม่


130

ใน Clojure ฉันต้องการรวมสองรายการเพื่อให้ได้รายชื่อคู่

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

ใน Haskell หรือทับทิมฟังก์ชั่นที่เรียกว่าซิป การนำไปใช้นั้นไม่ใช่เรื่องยาก แต่ฉันต้องการให้แน่ใจว่าฉันไม่พลาดฟังก์ชันใน Core หรือ Contrib

มีเนมสเปซzipใน Core แต่มีการอธิบายว่าให้การเข้าถึงเทคนิคการทำงานของซิปซึ่งดูเหมือนจะไม่ใช่สิ่งที่ฉันเป็น

มีฟังก์ชันที่เทียบเท่ากันสำหรับการรวม 2 รายการขึ้นไปด้วยวิธีนี้ใน Core หรือไม่?

ถ้าไม่มีนั่นเป็นเพราะมีวิธีการทางสำนวนที่ทำให้ฟังก์ชันไม่จำเป็นหรือไม่?


มีzipฟังก์ชันในไลบรารี Tupelo: cloojure.github.io/doc/tupelo/tupelo.core.html#var-zip
Alan Thompson

คำตอบ:


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

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

วิธีการสร้าง "ทูเพิล" ใน Clojure คือการสร้างเวกเตอร์สั้น ๆ ตามที่แสดงไว้ด้านบน

(เพื่อความสมบูรณ์โปรดทราบว่า Haskell ที่มีส่วนขยายพื้นฐานบางอย่างอนุญาตให้ใช้ฟังก์ชัน arity ตัวแปรการใช้งานต้องมีความเข้าใจภาษาเป็นอย่างดีและ vanilla Haskell 98 อาจไม่รองรับเลยดังนั้นฟังก์ชัน arity คงที่จึงเป็นที่ต้องการ สำหรับไลบรารีมาตรฐาน)


8
โปรดทราบว่าสิ่งนี้จะทำงานแตกต่างจากzipเมื่อคอลเล็กชันมีความยาวไม่เท่ากัน Ruby จะดำเนินการประมวลผลและจัดหาnils สำหรับคอลเล็กชันที่สั้นกว่าในขณะที่ Clojure จะหยุดประมวลผลเมื่อหนึ่งในคอลเล็กชันหมดลง
Nate W.

@NateW เป็นสิ่งที่ควรทราบขอบคุณ ใน Haskell zipมีพฤติกรรมเหมือน Clojure mapในแง่นี้
Michał Marczyk

1
ฉันขอข้อมูลอ้างอิงเกี่ยวกับฟังก์ชัน Haskell ตัวแปร arity ได้ไหม
Teodor

23
(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จับคู่ทั้งสองรายการจะทำให้คุณมีรายชื่อเหมือนในตัวอย่างของคุณ ฉันคิดว่าชาว 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))

1
ฉันคิดว่าคุณหมายถึง hash-map และ hash-set แทนที่จะเป็น map and set
cgrand

3

วิธีในตัวจะเป็นเพียงฟังก์ชัน 'interleave':

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

6
เพื่อให้บรรลุเป้าหมายของ OP คุณควรเพิ่ม(partition 2 (interleave [1 2 3 4][5 6 7 8]))
skuro

ใช่ - ดูเหมือนว่าฉันไม่ได้ดูผลลัพธ์ที่ต้องการของ OP อย่างใกล้ชิดเกินไป
lsh

-1

มีฟังก์ชันที่เรียกว่า zipmap ซึ่งอาจมีเอฟเฟกต์คล้ายกัน (zipmap (1 2 3)(4 5 6)) ouput เป็นเหมือน fllows: {3 6, 2 5, 1 4}


zipmap ส่งคืนแผนที่ให้คุณซึ่งไม่รับประกันการสั่งซื้อ
Ilya Shinkarenko

-2

# (ใช้รายการแผนที่%) เปลี่ยนเมทริกซ์เช่นเดียวกับฟังก์ชัน Python zip * เป็นนิยามมาโคร:

ผู้ใช้ => (defmacro py-zip [lst] `(ใช้รายการแผนที่ ~ lst))

# 'ผู้ใช้ / PY-Zip

ผู้ใช้ => (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))

ผู้ใช้ => (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))


วิธีนี้ดีกว่าการใช้ 'แผนที่' อย่างไร? แล้วมาโครตรงนี้คืออะไร?
Dave Newton
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.