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?
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:
Non dimentichiamo che il vecchio fidato into
ti consente di prendere qualsiasi cosa in seq
grado (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 into
in cima conj
alla raccolta e seq
.
Gli esempi precedenti si comporterebbero comunque bene se il destinatario venisse passato in fase di esecuzione: perché le astrazioni sottostanti ( seq
e 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.
into
usi conj
, il fare (into '() some-seq)
produrrà un elenco che è il contrario di alcuni-seq, perché si conj
traduce in elenchi.
into
utilizza transitori (per la maggior parte dei tipi di sequenze) per migliori caratteristiche di prestazione rispetto alla maggior parte degli altri mezzi di conversione.
vec
, set
E in generale into
sono 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?
Per i vettori c'è la vec
funzione
user=> (vec '(1 2 3))
[1 2 3]
Per le sequenze pigre c'è la lazy-seq
funzione
user=> (lazy-seq [1 2 3])
(1 2 3)
Per la conversione in set, c'è la set
funzione
user=> (set [{:a :b, :c :d} {:a :b} {:a :b}])
#{{:a :b} {:a :b, :c :d}}
lazy-seq
invece di seq
aggiungere 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.
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}
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 seq
sul vettore:
=> (seq [1 2 3])
(1 2 3)
for
te potresti semplicemente fare(map identity [1 2 3 4])
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}}