Di Clojure, apakah ada cara mudah untuk mengonversi di antara jenis daftar?

92

Saya sering menemukan diri saya menggunakan daftar malas ketika saya menginginkan vektor, dan sebaliknya. Juga, terkadang saya memiliki vektor peta, ketika saya benar-benar menginginkan satu set peta. Apakah ada fungsi pembantu untuk membantu saya mengonversi di antara tipe-tipe ini?

appshare.co
sumber

Jawaban:

147

Jangan lupa bahwa lama tepercaya intomemungkinkan Anda mengambil apa pun yang seqbisa (daftar, vektor, peta, set, sortir-peta) dan wadah kosong yang ingin Anda isi, dan letakkan 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"

intoadalah pembungkus conj, yang merupakan abstraksi dasar untuk menyisipkan entri baru secara tepat ke dalam koleksi berdasarkan jenis koleksi. Prinsip yang membuat aliran ini begitu bagus adalah bahwa Clojure dibangun di atas abstraksi yang dapat disusun , dalam hal ini intodi atas conjdi atas koleksi dan seq.

Contoh di atas akan tetap tersusun dengan baik jika penerima diteruskan pada waktu proses: karena abstraksi yang mendasarinya ( seqdan conj) diimplementasikan untuk semua koleksi (dan juga banyak koleksi Java), jadi abstraksi yang lebih tinggi tidak perlu khawatir tentang banyak kasus sudut khusus terkait data.

Arthur Ulfeldt
sumber
3
1 untuk ke ... perlu dicatat bahwa itu juga berfungsi dengan wadah asli yang tidak kosong juga (yaitu ketika Anda ingin menambahkan ke koleksi)
mikera
11
Ini juga diperhatikan bahwa karena intopenggunaan conj, melakukan (into '() some-seq)akan menghasilkan daftar itulah terbalik beberapa-seq, karena conjconses ke daftar.
Chuck
Perlu dicatat bahwa intomenggunakan transien (untuk sebagian besar jenis seq) untuk karakteristik kinerja yang lebih baik daripada kebanyakan cara konversi lainnya.
Jarred Humphrey
Dan sekarang berfungsi dengan transduser, yang tidak ada pada saat jawaban ini ditulis (saya tidak tahu apakah sementara juga) (Jawaban ini cukup tua untuk mendaftar di taman kanak-kanak)
Arthur Ulfeldt
33

vec, setdan biasanya intoteman Anda akan dengan mudah "mengonversi" ke jenis koleksi lain.

Bagaimana Anda ingin mengubah vektor peta menjadi peta peta? Anda memerlukan kunci, dapatkah Anda memberikan contoh masukan / keluaran yang diharapkan?

cgrand.dll
sumber
Maaf, maksud saya satu set peta .. Saya telah mengubah pertanyaannya sekarang
appshare.co
22

Untuk vektor ada vecfungsinya

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

Untuk urutan malas ada lazy-seqfungsinya

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

Untuk mengubahnya menjadi himpunan, ada setfungsinya

user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}
cobbal
sumber
4
Ketika Anda memiliki sesuatu yang tidak malas menelepon lazy-seqalih-alih seqhanya menambahkan tipuan yang tidak berguna. Jika benar-benar Anda ingin mengembalikan sesuatu yang tidak nihil bahkan sebelum koleksi kosong itu ada sequence. lazy-seqmerupakan konstruksi tingkat rendah.
cgrand
14

Satu lagi jawaban untuk mengubah dari daftar menjadi peta (demi kelengkapan) - dari sini :

(apply hash-map '(1 2 3 4))
;=>{1 2, 3 4}
hawkeye
sumber
9

Untuk mengonversi vektor menjadi daftar, Anda juga dapat menggunakan for, seperti ini:

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

Jika Anda tidak ingin memanipulasi data, gunakan saja seqpada vektor:

=> (seq [1 2 3])
(1 2 3)
Gubuk Geert-Jan
sumber
Alih-alih forAnda bisa melakukannya(map identity [1 2 3 4])
siltalau
7

Vektor tidak perlu diubah menjadi daftar. Clojure akan memperlakukan vektor sebagaimana ia akan memperlakukan daftar - sebagai urutan - bila urutan diperlukan. Sebagai contoh,

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

Jika Anda perlu memastikan bahwa vektor diperlakukan sebagai urutan, bungkus dalam 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)

Jika Anda memiliki vektor peta, dan Anda menginginkan satu set peta, tidak masalah bahwa vektor tersebut menyimpan peta. Anda cukup mengonversi vektor menjadi satu set seperti biasa:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}
Gambar kecil
sumber