ใน Clojure มีวิธีง่ายๆในการแปลงระหว่างประเภทรายการหรือไม่?


92

ฉันมักพบว่าตัวเองใช้รายการขี้เกียจเมื่อฉันต้องการเวกเตอร์และในทางกลับกัน นอกจากนี้บางครั้งฉันก็มีเวกเตอร์ของแผนที่เมื่อฉันต้องการชุดแผนที่จริงๆ มีฟังก์ชั่นตัวช่วยที่จะช่วยฉันในการแปลงระหว่างประเภทเหล่านี้หรือไม่?

คำตอบ:


147

อย่าลืมว่าของเก่าที่เชื่อถือได้intoช่วยให้คุณสามารถนำอะไรก็ได้seq(list, vector, map, set, sorted-map) และคอนเทนเนอร์ว่างเปล่าที่คุณต้องการเติมแล้วใส่intoลงไป

(into [] '(1 2 3 4)) ==> [1 2 3 4]         "have a lazy list and want a vector"
(into #{} [1 2 3 4]) ==> #{1 2 3 4}        "have a vector and want a set"
(into {} #{[1 2] [3 4]}) ==> {3 4, 1 2}    "have a set of vectors want a map"
(into #{} [{1 2} {3 4}]) ==> #{{1 2} {3 4}} "have a vector of maps want a set of maps"

intoเป็นกระดาษห่อหุ้มconjซึ่งเป็นนามธรรมพื้นฐานสำหรับการแทรกรายการใหม่ลงในคอลเล็กชันอย่างเหมาะสมตามประเภทของคอลเล็กชัน หลักการที่ทำให้การไหลนี้เพื่อให้เป็นอย่างดีก็คือว่าเป็น Clojure สร้างตามแนวคิด composableในกรณีนี้intoที่ด้านบนของด้านบนของคอลเลกชันและconjseq

ตัวอย่างข้างต้นจะยังคงเรียบเรียงได้ดีหากผู้รับถูกส่งต่อในเวลาดำเนินการ: เนื่องจาก abstractions พื้นฐาน ( seqและconj) ถูกนำไปใช้กับคอลเลกชันทั้งหมด (และคอลเลกชันของ Java จำนวนมากด้วย) ดังนั้นสิ่งที่เป็นนามธรรมที่สูงกว่าก็ไม่จำเป็นต้องกังวล เกี่ยวกับกรณีพิเศษที่เกี่ยวข้องกับข้อมูลจำนวนมาก


3
+1 ให้เป็น ... น่าสังเกตว่ามันยังใช้งานได้กับคอนเทนเนอร์ดั้งเดิมที่ไม่ว่างเปล่าเช่นกัน (เช่นเมื่อคุณต้องการเพิ่มในคอลเลกชัน)
mikera

11
นอกจากนี้ยังเป็นที่น่าสังเกตว่าเนื่องจากการintoใช้conjการทำ(into '() some-seq)จะทำให้ได้รายการที่ตรงกันข้ามกับบางส่วนเนื่องจากconjสอดคล้องกับรายการ
Chuck

เป็นที่น่าสังเกตว่าintoใช้ช่วงเวลาชั่วคราว (สำหรับประเภท seq ส่วนใหญ่) เพื่อให้ได้ลักษณะการทำงานที่ดีกว่าวิธีการแปลงอื่น ๆ ส่วนใหญ่
Jarred Humphrey

และตอนนี้ใช้งานได้กับทรานสดิวเซอร์ซึ่งไม่มีอยู่ในขณะที่เขียนคำตอบนี้ (ฉันไม่รู้ว่าชั่วคราวหรือไม่) (คำตอบนี้เก่าพอที่จะลงทะเบียนเรียนในโรงเรียนอนุบาล)
Arthur Ulfeldt

33

vec, setและโดยทั่วไปจะintoเป็นเพื่อนของคุณได้อย่างง่ายดาย "แปลง" ประเภทคอลเลกชันอื่น

คุณต้องการเปลี่ยนเวกเตอร์ของแผนที่เป็นแผนที่ของแผนที่อย่างไร? คุณต้องการคีย์คุณสามารถใช้กับอินพุตตัวอย่าง / เอาต์พุตที่คาดหวังได้หรือไม่?


ขออภัยฉันหมายถึงชุดแผนที่ .. ตอนนี้ฉันได้แก้ไขคำถามแล้ว
appshare.co

22

สำหรับเวกเตอร์มีvecฟังก์ชัน

user=> (vec '(1 2 3))
[1 2 3]

สำหรับลำดับที่ขี้เกียจมีไฟล์ lazy-seqฟังก์ชั่น

user=> (lazy-seq [1 2 3])
(1 2 3)

สำหรับการแปลงเป็นเซตมีsetฟังก์ชัน

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}

4
เมื่อคุณมีบางสิ่งบางอย่างที่ไม่ขี้เกียจโทรlazy-seqแทนที่จะseqเพิ่มทิศทางที่ไร้ประโยชน์ จริงๆถ้าคุณต้องการที่จะกลับมาบางสิ่งบางอย่างที่ไม่ใช่ศูนย์แม้ก่อนล้าง collectiosn thene sequenceมี lazy-seqเป็นโครงสร้างระดับต่ำ
cgrand


9

ในการแปลงเวกเตอร์เป็นรายการคุณสามารถใช้forดังนี้:

=> (for [i [1 2 3 4]] i)
(1 2 3 4)

เมื่อคุณไม่ต้องการจัดการข้อมูลให้ใช้seqกับเวกเตอร์:

=> (seq [1 2 3])
(1 2 3)

แทนที่forคุณจะทำได้(map identity [1 2 3 4])
siltalau

7

ไม่จำเป็นต้องแปลงเวกเตอร์เป็นรายการ Clojure จะปฏิบัติต่อเวกเตอร์เหมือนกับที่จะปฏิบัติต่อรายการ - เป็นลำดับ - เมื่อต้องใช้ลำดับ ตัวอย่างเช่น,

user=> (cons 0 [1 2 3])
(0 1 2 3)

หากคุณต้องการตรวจสอบให้แน่ใจว่าเวกเตอร์ได้รับการปฏิบัติตามลำดับให้รวมไว้ในseq:

user=> (conj [1 2 3] 0) ; treated as a vector
[1 2 3 0]

user=> (conj (seq [1 2 3]) 0) ; treated as a sequence
(0 1 2 3)

หากคุณมีเวกเตอร์ของแผนที่และคุณต้องการชุดแผนที่ก็ไม่สำคัญว่าเวกเตอร์นั้นจะมีแผนที่ คุณเพียงแค่แปลงเวกเตอร์เป็นชุดตามปกติ:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.