In Clojure c'è un modo semplice per convertire tra i tipi di lista?


92

Spesso mi ritrovo a utilizzare una lista pigra quando voglio un vettore e viceversa. Inoltre, a volte ho un vettore di mappe, quando volevo davvero un set di mappe. Esistono funzioni di supporto per aiutarmi a convertire tra questi tipi?

Risposte:


144

Non dimentichiamo che il vecchio fidato intoti consente di prendere qualsiasi cosa in seqgrado (elenco, vettore, mappa, set, mappa ordinata) e un contenitore vuoto che vuoi riempire, e lo inserisce 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è un wrapper conj, che è l'astrazione di base per inserire nuove voci in modo appropriato in una raccolta in base al tipo di raccolta. Il principio che rende questo flusso così piacevole è che Clojure si basa su astrazioni componibili , in questo caso intoin cima conjalla raccolta e seq.

Gli esempi precedenti si comporterebbero comunque bene se il destinatario venisse passato in fase di esecuzione: perché le astrazioni sottostanti ( seqe conj) sono implementate per tutte le raccolte (e anche molte raccolte di Java), quindi le astrazioni superiori non devono preoccuparsi su molti casi speciali relativi ai dati.


3
+1 per in ... vale la pena notare che funziona anche con contenitori originali non vuoti (cioè quando si desidera aggiungere a una raccolta)
mikera

11
Vale anche la pena notare che, poiché gli intousi conj, il fare (into '() some-seq)produrrà un elenco che è il contrario di alcuni-seq, perché si conjtraduce in elenchi.
Chuck

Vale la pena notare che intoutilizza transitori (per la maggior parte dei tipi di sequenze) per migliori caratteristiche di prestazione rispetto alla maggior parte degli altri mezzi di conversione.
Jarred Humphrey

E ora funziona con i trasduttori, che non esistevano al momento in cui è stata scritta questa risposta (non so se anche i transitori lo facessero) (Questa risposta è abbastanza vecchia per iscriversi all'asilo)
Arthur Ulfeldt

33

vec, setE in generale intosono i tuoi amici in modo semplice "Convert" per un altro tipo di raccolta.

Come vuoi trasformare un vettore di mappe in una mappa di mappe? Hai bisogno di una chiave, puoi fornire l'uso con input di esempio / output previsto?


Scusa, intendevo un set di mappe .. Ho modificato la domanda ora
appshare.co

22

Per i vettori c'è la vecfunzione

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

Per le sequenze pigre c'è la lazy-seqfunzione

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

Per la conversione in set, c'è la setfunzione

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

4
Quando hai qualcosa di non pigro che chiama lazy-seqinvece di seqaggiungere solo un inutile indiretto. Se davvero vuoi restituire qualcosa di non nullo anche prima della raccolta vuota, allora c'è sequence. lazy-seqè un po 'un costrutto di basso livello.
cgrand

14

Un'altra risposta per la conversione da un elenco a una mappa (per completezza) - da qui :

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

9

Per convertire un vettore in un elenco puoi anche usare for, in questo modo:

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

Quando non vuoi manipolare i dati, usa semplicemente seqsul vettore:

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

Invece di forte potresti semplicemente fare(map identity [1 2 3 4])
siltalau

7

Non è necessario convertire un vettore in un elenco. Clojure tratterà un vettore come tratterebbe un elenco - come una sequenza - quando è richiesta una sequenza. Per esempio,

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

Se devi assicurarti che il vettore venga trattato come una sequenza, racchiudilo in 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)

Se si dispone di un vettore di mappe e si desidera un insieme di mappe, non importa che il vettore contenga mappe. Devi solo convertire il vettore in un set come al solito:

user=> (set [{:a 1, :b 2} {"three" 3, "four" 4}])
#{{:a 1, :b 2} {"four" 4, "three" 3}}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.