clojure
Collezioni e sequenze
Ricerca…
Sintassi
-
'()
→()
-
'(1 2 3 4 5)
→(1 2 3 4 5)
-
'(1 foo 2 bar 3)
→(1 'foo 2 'bar 3)
-
(
list
1 2 3 4 5)
→(1 2 3 4 5)
-
(
list*
[1 2 3 4 5])
→(1 2 3 4 5)
-
[]
→[]
-
[1 2 3 4 5]
→[1 2 3 4 5]
-
(
vector
1 2 3 4 5)
→[1 2 3 4 5]
-
(
vec
'(1 2 3 4 5))
→[1 2 3 4 5]
-
{}
=>{}
-
{:keyA 1 :keyB 2}
→{:keyA 1 :keyB 2}
-
{:keyA 1, :keyB 2}
→{:keyA 1 :keyB 2}
-
(
hash-map
:keyA 1 :keyB 2)
→{:keyA 1 :keyB 2}
-
(
sorted-map
5 "five" 1 "one")
→{1 "one" 5 "five"}
(le voci sono ordinate per tasto quando usate come sequenza) -
#{}
→#{}
-
#{1 2 3 4 5}
→#{4 3 2 5 1}
(non ordinato) -
(
hash-set
1 2 3 4 5)
→#{2 5 4 1 3}
(non ordinato) -
(
sorted-set
2 5 4 3 1)
→#{1 2 3 4 5}
collezioni
Tutte le raccolte Clojure incorporate sono immutabili ed eterogenee, hanno una sintassi letterale e supportano le funzioni conj
, count
e seq
.
-
conj
restituisce una nuova collezione che è equivalente a una collezione esistente con un elemento "aggiunto", in "tempo costante" o logaritmico. Cosa significa esattamente questo dipende dalla collezione. -
count
restituisce il numero di elementi in una raccolta, in tempo costante. -
seq
restituiscenil
per una raccolta vuota o una sequenza di elementi per una raccolta non vuota, in tempo costante.
elenchi
Una lista è denotata da parentesi:
()
;;=> ()
Una lista di Clojure è una lista concatenata . conj
"unisce" un nuovo elemento alla collezione nella posizione più efficiente. Per gli elenchi, questo è all'inizio:
(conj () :foo)
;;=> (:foo)
(conj (conj () :bar) :foo)
;;=> (:foo :bar)
A differenza di altre raccolte, gli elenchi non vuoti vengono valutati come chiamate a moduli speciali, macro o funzioni quando vengono valutati. Pertanto, mentre (:foo)
è la rappresentazione letterale della lista che contiene :foo
come unico elemento, la valutazione (:foo)
in un REPL causerà il IllegalArgumentException
di IllegalArgumentException
perché una parola chiave non può essere invocata come una funzione nulla .
(:foo)
;; java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :foo
Per evitare che Clojure valuti un elenco non vuoto, puoi quote
:
'(:foo)
;;=> (:foo)
'(:foo :bar)
;;=> (:foo :bar)
Sfortunatamente, questo non causa la valutazione degli elementi:
(+ 1 1)
;;=> 2
'(1 (+ 1 1) 3)
;;=> (1 (+ 1 1) 3)
Per questo motivo, di solito vuoi usare la list
, una funzione variadica che valuta tutti i suoi argomenti e usa quei risultati per costruire una lista:
(list)
;;=> ()
(list :foo)
;;=> (:foo)
(list :foo :bar)
;;=> (:foo :bar)
(list 1 (+ 1 1) 3)
;;=> (1 2 3)
count
restituisce il numero di elementi, in tempo costante:
(count ())
;;=> 0
(count (conj () :foo))
;;=> 1
(count '(:foo :bar))
;;=> 2
Puoi verificare se qualcosa è una lista usando l' list?
predicato:
(list? ())
;;=> true
(list? '(:foo :bar))
;;=> true
(list? nil)
;;=> false
(list? 42)
;;=> false
(list? :foo)
;;=> false
È possibile ottenere il primo elemento di una lista usando peek
:
(peek ())
;;=> nil
(peek '(:foo))
;;=> :foo
(peek '(:foo :bar))
;;=> :foo
Puoi ottenere una nuova lista senza il primo elemento usando pop
:
(pop '(:foo))
;;=> ()
(pop '(:foo :bar))
;;=> (:bar)
Si noti che se si tenta di pop
un elenco vuoto, si otterrà un IllegalStateException
:
(pop ())
;; java.lang.IllegalStateException: Can't pop empty list
Infine, tutte le liste sono sequenze, quindi puoi fare tutto con una lista che puoi fare con qualsiasi altra sequenza. Infatti, con l'eccezione della lista vuota, chiamare seq
su una lista restituisce lo stesso identico oggetto:
(seq ())
;;=> nil
(seq '(:foo))
;;=> (:foo)
(seq '(:foo :bar))
;;=> (:foo :bar)
(let [x '(:foo :bar)]
(identical? x (seq x)))
;;=> true
sequenze
Una sequenza è molto simile a una lista: è un oggetto immutabile che può darti il suo first
elemento o il rest
dei suoi elementi in un tempo costante. È possibile anche cons
truct una nuova sequenza da una sequenza esistente e un elemento di attenersi al principio.
Puoi verificare se qualcosa è una sequenza usando il seq?
predicato:
(seq? nil)
;;=> false
(seq? 42)
;;=> false
(seq? :foo)
;;=> false
Come già sai, le liste sono sequenze:
(seq? ())
;;=> true
(seq? '(:foo :bar))
;;=> true
Tutto ciò che ottieni chiamando seq
o rseq
o keys
o vals
su una raccolta non vuota è anche una sequenza:
(seq? (seq ()))
;;=> false
(seq? (seq '(:foo :bar)))
;;=> true
(seq? (seq []))
;;=> false
(seq? (seq [:foo :bar]))
;;=> true
(seq? (rseq []))
;;=> false
(seq? (rseq [:foo :bar]))
;;=> true
(seq? (seq {}))
;;=> false
(seq? (seq {:foo :bar :baz :qux}))
;;=> true
(seq? (keys {}))
;;=> false
(seq? (keys {:foo :bar :baz :qux}))
;;=> true
(seq? (vals {}))
;;=> false
(seq? (vals {:foo :bar :baz :qux}))
;;=> true
(seq? (seq #{}))
;;=> false
(seq? (seq #{:foo :bar}))
;;=> true
Ricorda che tutte le liste sono sequenze, ma non tutte le sequenze sono elenchi. Mentre le liste supportano lo peek
e il pop
e count
in un tempo costante, in generale, una sequenza non ha bisogno di supportare nessuna di quelle funzioni. Se provi a chiamare peek
o pop
su una sequenza che non supporta anche l'interfaccia stack di Clojure, otterrai una ClassCastException
:
(peek (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack
(pop (seq [:foo :bar]))
;; java.lang.ClassCastException: clojure.lang.PersistentVector$ChunkedSeq cannot be cast to clojure.lang.IPersistentStack
(peek (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack
(pop (seq #{:foo :bar}))
;; java.lang.ClassCastException: clojure.lang.APersistentMap$KeySeq cannot be cast to clojure.lang.IPersistentStack
(peek (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack
(pop (seq {:foo :bar :baz :qux}))
;; java.lang.ClassCastException: clojure.lang.PersistentArrayMap$Seq cannot be cast to clojure.lang.IPersistentStack
Se si chiama count
su una sequenza che non implementa il count
in tempo costante, non si otterrà un errore; invece, Clojure attraverserà l'intera sequenza fino a raggiungere la fine, quindi restituirà il numero di elementi che ha attraversato. Ciò significa che, per le sequenze generali, il count
è un tempo lineare, non costante. È possibile verificare se qualcosa supporta il count
tempo costante utilizzando il counted?
predicato:
(counted? '(:foo :bar))
;;=> true
(counted? (seq '(:foo :bar)))
;;=> true
(counted? [:foo :bar])
;;=> true
(counted? (seq [:foo :bar]))
;;=> true
(counted? {:foo :bar :baz :qux})
;;=> true
(counted? (seq {:foo :bar :baz :qux}))
;;=> true
(counted? #{:foo :bar})
;;=> true
(counted? (seq #{:foo :bar}))
;;=> false
Come accennato in precedenza, è possibile utilizzare first
per ottenere il primo elemento di una sequenza. Nota che first
chiameremo seq
sul loro argomento, quindi può essere usato su qualsiasi cosa "seqable", non solo sulle sequenze effettive:
(first nil)
;;=> nil
(first '(:foo))
;;=> :foo
(first '(:foo :bar))
;;=> :foo
(first [:foo])
;;=> :foo
(first [:foo :bar])
;;=> :foo
(first {:foo :bar})
;;=> [:foo :bar]
(first #{:foo})
;;=> :foo
Inoltre, come menzionato sopra, puoi usare il rest
per ottenere una sequenza che contiene tutto tranne il primo elemento di una sequenza esistente. Come first
, chiama seq
sulla sua argomentazione. Tuttavia, non chiama seq
sul suo risultato! Ciò significa che, se chiami il rest
su una sequenza che contiene meno di due elementi, tornerai indietro ()
invece di nil
:
(rest nil)
;;=> ()
(rest '(:foo))
;;=> ()
(rest '(:foo :bar))
;;=> (:bar)
(rest [:foo])
;;=> ()
(rest [:foo :bar])
;;=> (:bar)
(rest {:foo :bar})
;;=> ()
(rest #{:foo})
;;=> ()
Se si vuole tornare nil
, quando non ci sono più elementi in una sequenza, è possibile utilizzare next
posto di rest
:
(next nil)
;;=> nil
(next '(:foo))
;;=> nil
(next [:foo])
;;=> nil
È possibile utilizzare la funzione cons
per creare una nuova sequenza che restituirà il primo argomento per il first
e il secondo argomento per il rest
:
(cons :foo nil)
;;=> (:foo)
(cons :foo (cons :bar nil))
;;=> (:foo :bar)
Clojure offre una grande libreria di sequenze con molte funzioni per gestire le sequenze. La cosa importante di questa libreria è che funziona con qualsiasi cosa "seqable", non solo con le liste. Ecco perché il concetto di una sequenza è così utile; significa che una singola funzione, come reduce
, funziona perfettamente su qualsiasi raccolta:
(reduce + '(1 2 3))
;;=> 6
(reduce + [1 2 3])
;;=> 6
(reduce + #{1 2 3})
;;=> 6
L'altra ragione per cui le sequenze sono utili è che, poiché non impongono alcuna particolare implementazione del first
e del rest
, consentono sequenze pigre i cui elementi vengono realizzati solo quando necessario.
Data un'espressione che creerebbe una sequenza, puoi avvolgere quell'espressione nella macro lazy-seq
per ottenere un oggetto che si comporta come una sequenza, ma in realtà valuterà quell'espressione solo quando viene richiesta dalla funzione seq
, a che punto sarà cache il risultato dell'espressione e in avanti first
e rest
chiamate al risultato in cache.
Per le sequenze finite, una sequenza lenta di solito agisce come una sequenza desiderosa equivalente:
(seq [:foo :bar])
;;=> (:foo :bar)
(lazy-seq [:foo :bar])
;;=> (:foo :bar)
Tuttavia, la differenza diventa evidente per le sequenze infinite:
(defn eager-fibonacci [a b]
(cons a (eager-fibonacci b (+' a b))))
(defn lazy-fibonacci [a b]
(lazy-seq (cons a (lazy-fibonacci b (+' a b)))))
(take 10 (eager-fibonacci 0 1))
;; java.lang.StackOverflowError:
(take 10 (lazy-fibonacci 0 1))
;;=> (0 1 1 2 3 5 8 13 21 34)
Vettori
Un vettore è indicato da parentesi quadre:
[]
;;=> []
[:foo]
;;=> [:foo]
[:foo :bar]
;;=> [:foo :bar]
[1 (+ 1 1) 3]
;;=> [1 2 3]
Inoltre, utilizzando la sintassi letterale, puoi anche utilizzare la funzione vector
per costruire un vettore:
(vector)
;;=> []
(vector :foo)
;;=> [:foo]
(vector :foo :bar)
;;=> [:foo :bar]
(vector 1 (+ 1 1) 3)
;;=> [1 2 3]
Puoi verificare se qualcosa è un vettore che usa il vector?
predicato:
(vector? [])
;;=> true
(vector? [:foo :bar])
;;=> true
(vector? nil)
;;=> false
(vector? 42)
;;=> false
(vector? :foo)
;;=> false
conj
aggiunge elementi alla fine di un vettore:
(conj [] :foo)
;;=> [:foo]
(conj (conj [] :foo) :bar)
;;=> [:foo :bar]
(conj [] :foo :bar)
;;=> [:foo :bar]
count
restituisce il numero di elementi, in tempo costante:
(count [])
;;=> 0
(count (conj [] :foo))
;;=> 1
(count [:foo :bar])
;;=> 2
Puoi ottenere l'ultimo elemento di un vettore usando la peek
:
(peek [])
;;=> nil
(peek [:foo])
;;=> :foo
(peek [:foo :bar])
;;=> :bar
Puoi ottenere un nuovo vettore senza l'ultimo elemento usando pop
:
(pop [:foo])
;;=> []
(pop [:foo :bar])
;;=> [:foo]
Nota che se provi a far IllegalStateException
un vettore vuoto, otterrai una IllegalStateException
:
(pop [])
;; java.lang.IllegalStateException: Can't pop empty vector
A differenza delle liste, i vettori sono indicizzati. Puoi ottenere un elemento di un vettore per indice in tempo "costante" usando get
:
(get [:foo :bar] 0)
;;=> :foo
(get [:foo :bar] 1)
;;=> :bar
(get [:foo :bar] -1)
;;=> nil
(get [:foo :bar] 2)
;;=> nil
Inoltre, i vettori stessi sono funzioni che prendono un indice e restituiscono l'elemento in quell'indice:
([:foo :bar] 0)
;;=> :foo
([:foo :bar] 1)
;;=> :bar
Tuttavia, se chiami un vettore con un indice non valido, otterrai un valore IndexOutOfBoundsException
anziché nil
:
([:foo :bar] -1)
;; java.lang.IndexOutOfBoundsException:
([:foo :bar] 2)
;; java.lang.IndexOutOfBoundsException:
Puoi ottenere un nuovo vettore con un valore diverso in un indice particolare usando assoc
:
(assoc [:foo :bar] 0 42)
;;=> [42 :bar]
(assoc [:foo :bar] 1 42)
;;=> [:foo 42]
Se passi un indice uguale al count
del vettore, Clojure aggiungerà l'elemento come se avessi usato il conj
. Tuttavia, se si passa un indice negativo o superiore al count
, si otterrà un valore IndexOutOfBoundsException
:
(assoc [:foo :bar] 2 42)
;;=> [:foo :bar 42]
(assoc [:foo :bar] -1 42)
;; java.lang.IndexOutOfBoundsException:
(assoc [:foo :bar] 3 42)
;; java.lang.IndexOutOfBoundsException:
Puoi ottenere una sequenza degli elementi in un vettore usando seq
:
(seq [])
;;=> nil
(seq [:foo])
;;=> (:foo)
(seq [:foo :bar])
;;=> (:foo :bar)
Poiché i vettori sono indicizzati, puoi anche ottenere una sequenza invertita degli elementi di un vettore usando rseq
:
(rseq [])
;;=> nil
(rseq [:foo])
;;=> (:foo)
(rseq [:foo :bar])
;;=> (:bar :foo)
Si noti che, sebbene tutte le liste siano sequenze e le sequenze siano visualizzate allo stesso modo delle liste, non tutte le sequenze sono elenchi!
'(:foo :bar)
;;=> (:foo :bar)
(seq [:foo :bar])
;;=> (:foo :bar)
(list? '(:foo :bar))
;;=> true
(list? (seq [:foo :bar]))
;;=> false
(list? (rseq [:foo :bar]))
;;=> false
Imposta
Come le mappe, gli insiemi sono associativi e non ordinati. A differenza delle mappe, che contengono mappature da chiavi a valori, imposta essenzialmente la mappa da chiavi a se stesse.
Un set è denotato da parentesi graffe precedute da un octothorpe:
#{}
;;=> #{}
#{:foo}
;;=> #{:foo}
#{:foo :bar}
;;=> #{:bar :foo}
Come con le mappe, l'ordine in cui gli elementi appaiono in un set letterale non ha importanza:
(= #{:foo :bar} #{:bar :foo})
;;=> true
Puoi verificare se qualcosa è un set usando il set?
predicato:
(set? #{})
;;=> true
(set? #{:foo})
;;=> true
(set? #{:foo :bar})
;;=> true
(set? nil)
;;=> false
(set? 42)
;;=> false
(set? :foo)
;;=> false
È possibile verificare se una mappa contiene un dato elemento in "costante" utilizzando il contains?
predicato:
(contains? #{} :foo)
;;=> false
(contains? #{:foo} :foo)
;;=> true
(contains? #{:foo} :bar)
;;=> false
(contains? #{} nil)
;;=> false
(contains? #{nil} nil)
;;=> true
Inoltre, gli insiemi stessi sono funzioni che accettano un elemento e restituiscono quell'elemento se è presente nell'insieme, o nil
se non lo è:
(#{} :foo)
;;=> nil
(#{:foo} :foo)
;;=> :foo
(#{:foo} :bar)
;;=> nil
(#{} nil)
;;=> nil
(#{nil} nil)
;;=> nil
Puoi usare conj
per ottenere un set che ha tutti gli elementi di un set esistente, oltre a un elemento aggiuntivo:
(conj #{} :foo)
;;=> #{:foo}
(conj (conj #{} :foo) :bar)
;;=> #{:bar :foo}
(conj #{:foo} :foo)
;;=> #{:foo}
Puoi usare disj
per ottenere un set che ha tutti gli elementi di un set esistente, meno un elemento:
(disj #{} :foo)
;;=> #{}
(disj #{:foo} :foo)
;;=> #{}
(disj #{:foo} :bar)
;;=> #{:foo}
(disj #{:foo :bar} :foo)
;;=> #{:bar}
(disj #{:foo :bar} :bar)
;;=> #{:foo}
count
restituisce il numero di elementi, in tempo costante:
(count #{})
;;=> 0
(count (conj #{} :foo))
;;=> 1
(count #{:foo :bar})
;;=> 2
Puoi ottenere una sequenza di tutti gli elementi in un set usando seq
:
(seq #{})
;;=> nil
(seq #{:foo})
;;=> (:foo)
(seq #{:foo :bar})
;;=> (:bar :foo)
Mappe
A differenza della lista, che è una struttura dati sequenziale, e del vettore, che è sia sequenziale che associativo, la mappa è esclusivamente una struttura di dati associativa. Una mappa consiste in un insieme di mappature dalle chiavi ai valori. Tutte le chiavi sono univoche, quindi le mappe supportano la ricerca "costante" -time dalle chiavi ai valori.
Una mappa è denotata da parentesi graffe:
{}
;;=> {}
{:foo :bar}
;;=> {:foo :bar}
{:foo :bar :baz :qux}
;;=> {:foo :bar, :baz :qux}
Ogni coppia di due elementi è una coppia chiave-valore. Quindi, ad esempio, la prima mappa in alto non ha mappature. Il secondo ha una mappatura, dalla chiave :foo
al valore :bar
. Il terzo ha due mapping, uno dalla chiave :foo
al valore :bar
, e uno dalla chiave :baz
al valore :qux
. Le mappe sono intrinsecamente non ordinate, quindi l'ordine in cui appaiono i mapping non ha importanza:
(= {:foo :bar :baz :qux}
{:baz :qux :foo :bar})
;;=> true
Puoi verificare se qualcosa è una mappa usando la map?
predicato:
(map? {})
;;=> true
(map? {:foo :bar})
;;=> true
(map? {:foo :bar :baz :qux})
;;=> true
(map? nil)
;;=> false
(map? 42)
;;=> false
(map? :foo)
;;=> false
È possibile verificare se una mappa contiene una determinata chiave in "costante" utilizzando il contains?
predicato:
(contains? {:foo :bar :baz :qux} 42)
;;=> false
(contains? {:foo :bar :baz :qux} :foo)
;;=> true
(contains? {:foo :bar :baz :qux} :bar)
;;=> false
(contains? {:foo :bar :baz :qux} :baz)
;;=> true
(contains? {:foo :bar :baz :qux} :qux)
;;=> false
(contains? {:foo nil} :foo)
;;=> true
(contains? {:foo nil} :bar)
;;=> false
Puoi ottenere il valore associato a una chiave usando get
:
(get {:foo :bar :baz :qux} 42)
;;=> nil
(get {:foo :bar :baz :qux} :foo)
;;=> :bar
(get {:foo :bar :baz :qux} :bar)
;;=> nil
(get {:foo :bar :baz :qux} :baz)
;;=> :qux
(get {:foo :bar :baz :qux} :qux)
;;=> nil
(get {:foo nil} :foo)
;;=> nil
(get {:foo nil} :bar)
;;=> nil
Inoltre, le mappe stesse sono funzioni che accettano una chiave e restituiscono il valore associato a quella chiave:
({:foo :bar :baz :qux} 42)
;;=> nil
({:foo :bar :baz :qux} :foo)
;;=> :bar
({:foo :bar :baz :qux} :bar)
;;=> nil
({:foo :bar :baz :qux} :baz)
;;=> :qux
({:foo :bar :baz :qux} :qux)
;;=> nil
({:foo nil} :foo)
;;=> nil
({:foo nil} :bar)
;;=> nil
Puoi trovare un'intera voce della mappa (chiave e valore insieme) come vettore a due elementi usando find
:
(find {:foo :bar :baz :qux} 42)
;;=> nil
(find {:foo :bar :baz :qux} :foo)
;;=> [:foo :bar]
(find {:foo :bar :baz :qux} :bar)
;;=> nil
(find {:foo :bar :baz :qux} :baz)
;;=> [:baz :qux]
(find {:foo :bar :baz :qux} :qux)
;;=> nil
(find {:foo nil} :foo)
;;=> [:foo nil]
(find {:foo nil} :bar)
;;=> nil
È possibile estrarre la chiave o il valore da una voce della mappa utilizzando la key
o val
, rispettivamente:
(key (find {:foo :bar} :foo))
;;=> :foo
(val (find {:foo :bar} :foo))
;;=> :bar
Si noti che, sebbene tutte le voci della mappa Clojure siano vettori, non tutti i vettori sono voci della mappa. Se provi a chiamare la key
o val
su qualsiasi cosa che non è una voce della mappa, otterrai una ClassCastException
:
(key [:foo :bar])
;; java.lang.ClassCastException:
(val [:foo :bar])
;; java.lang.ClassCastException:
Puoi verificare se qualcosa è una voce della map-entry?
usando la voce della map-entry?
predicato:
(map-entry? (find {:foo :bar} :foo))
;;=> true
(map-entry? [:foo :bar])
;;=> false
Puoi utilizzare assoc
per ottenere una mappa che abbia tutte le stesse coppie chiave-valore di una mappa esistente, con una mappatura aggiunta o modificata:
(assoc {} :foo :bar)
;;=> {:foo :bar}
(assoc (assoc {} :foo :bar) :baz :qux)
;;=> {:foo :bar, :baz :qux}
(assoc {:baz :qux} :foo :bar)
;;=> {:baz :qux, :foo :bar}
(assoc {:foo :bar :baz :qux} :foo 42)
;;=> {:foo 42, :baz :qux}
(assoc {:foo :bar :baz :qux} :baz 42)
;;=> {:foo :bar, :baz 42}
Puoi usare dissoc
per ottenere una mappa che abbia tutte le stesse coppie chiave-valore di una mappa esistente, con eventualmente una mappatura rimossa:
(dissoc {:foo :bar :baz :qux} 42)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo :bar :baz :qux} :foo)
;;=> {:baz :qux}
(dissoc {:foo :bar :baz :qux} :bar)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo :bar :baz :qux} :baz)
;;=> {:foo :bar}
(dissoc {:foo :bar :baz :qux} :qux)
;;=> {:foo :bar :baz :qux}
(dissoc {:foo nil} :foo)
;;=> {}
count
restituisce il numero di mapping, in tempo costante:
(count {})
;;=> 0
(count (assoc {} :foo :bar))
;;=> 1
(count {:foo :bar :baz :qux})
;;=> 2
Puoi ottenere una sequenza di tutte le voci in una mappa usando seq
:
(seq {})
;;=> nil
(seq {:foo :bar})
;;=> ([:foo :bar])
(seq {:foo :bar :baz :qux})
;;=> ([:foo :bar] [:baz :qux])
Di nuovo, le mappe non sono ordinate, quindi l'ordinamento degli elementi in una sequenza che ottieni chiamando seq
su una mappa non è definito.
È possibile ottenere una sequenza di soli i tasti o solo i valori in una mappa utilizzando keys
o vals
, rispettivamente:
(keys {})
;;=> nil
(keys {:foo :bar})
;;=> (:foo)
(keys {:foo :bar :baz :qux})
;;=> (:foo :baz)
(vals {})
;;=> nil
(vals {:foo :bar})
;;=> (:bar)
(vals {:foo :bar :baz :qux})
;;=> (:bar :qux)
Clojure 1.9 aggiunge una sintassi letterale per rappresentare in modo più conciso una mappa in cui le chiavi condividono lo stesso spazio dei nomi. Si noti che la mappa in entrambi i casi è identica (la mappa non "conosce" lo spazio dei nomi predefinito), questa è solo una comodità sintattica.
;; typical map syntax
(def p {:person/first"Darth" :person/last "Vader" :person/email "[email protected]"})
;; namespace map literal syntax
(def p #:person{:first "Darth" :last "Vader" :email "[email protected]"})