clojure
Colecciones y secuencias
Buscar..
Sintaxis
-
'()
→()
-
'(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"}
(las entradas se ordenan por clave cuando se usan como una secuencia) -
#{}
→#{}
-
#{1 2 3 4 5}
→#{4 3 2 5 1}
(sin ordenar) -
(
hash-set
1 2 3 4 5)
→#{2 5 4 1 3}
(sin ordenar) -
(
sorted-set
2 5 4 3 1)
→#{1 2 3 4 5}
Colecciones
Todas las colecciones de Clojure integradas son inmutables y heterogéneas, tienen una sintaxis literal y admiten las funciones conj
, count
y seq
.
-
conj
devuelve una nueva colección que es equivalente a una colección existente con un elemento "agregado", ya sea en "constante" o tiempo logarítmico. Lo que exactamente esto significa depende de la colección. -
count
devuelve el número de elementos en una colección, en tiempo constante. -
seq
devuelvenil
para una colección vacía, o una secuencia de elementos para una colección no vacía, en tiempo constante.
Liza
Una lista se denota entre paréntesis:
()
;;=> ()
Una lista de Clojure es una lista enlazada individualmente . conj
"combina" un nuevo elemento de la colección en la ubicación más eficiente. Para listas, esto es al principio:
(conj () :foo)
;;=> (:foo)
(conj (conj () :bar) :foo)
;;=> (:foo :bar)
A diferencia de otras colecciones, las listas no vacías se evalúan como llamadas a formularios especiales, macros o funciones cuando se evalúan. Por lo tanto, mientras que (:foo)
es la representación literal de la lista que contiene :foo
como su único elemento, evaluar (:foo)
en un REPL provocará que se IllegalArgumentException
una IllegalArgumentException
porque una palabra clave no puede invocarse como una función nula .
(:foo)
;; java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :foo
Para evitar que Clojure evalúe una lista no vacía, puede quote
:
'(:foo)
;;=> (:foo)
'(:foo :bar)
;;=> (:foo :bar)
Desafortunadamente, esto hace que los elementos no sean evaluados:
(+ 1 1)
;;=> 2
'(1 (+ 1 1) 3)
;;=> (1 (+ 1 1) 3)
Por esta razón, normalmente querrá usar list
, una función variadic que evalúa todos sus argumentos y utiliza esos resultados para construir una lista:
(list)
;;=> ()
(list :foo)
;;=> (:foo)
(list :foo :bar)
;;=> (:foo :bar)
(list 1 (+ 1 1) 3)
;;=> (1 2 3)
count
devuelve el número de elementos, en tiempo constante:
(count ())
;;=> 0
(count (conj () :foo))
;;=> 1
(count '(:foo :bar))
;;=> 2
¿Puedes probar si algo es una lista usando la list?
predicado:
(list? ())
;;=> true
(list? '(:foo :bar))
;;=> true
(list? nil)
;;=> false
(list? 42)
;;=> false
(list? :foo)
;;=> false
Puedes obtener el primer elemento de una lista usando peek
:
(peek ())
;;=> nil
(peek '(:foo))
;;=> :foo
(peek '(:foo :bar))
;;=> :foo
Puedes obtener una nueva lista sin el primer elemento usando pop
:
(pop '(:foo))
;;=> ()
(pop '(:foo :bar))
;;=> (:bar)
Tenga en cuenta que si intenta pop
una lista vacía, obtendrá un IllegalStateException
:
(pop ())
;; java.lang.IllegalStateException: Can't pop empty list
Finalmente, todas las listas son secuencias, por lo que puede hacer todo con una lista que puede hacer con cualquier otra secuencia. De hecho, con la excepción de la lista vacía, llamar a seq
en una lista devuelve el mismo objeto exacto:
(seq ())
;;=> nil
(seq '(:foo))
;;=> (:foo)
(seq '(:foo :bar))
;;=> (:foo :bar)
(let [x '(:foo :bar)]
(identical? x (seq x)))
;;=> true
Secuencias
Una secuencia es muy parecida a una lista: es un objeto inmutable que puede darle su first
elemento o el rest
de sus elementos en tiempo constante. También puede cons
truct una nueva secuencia de una secuencia existente y un elemento para pegarse al principio.
Puedes probar si algo es una secuencia usando la secuencia seq?
predicado:
(seq? nil)
;;=> false
(seq? 42)
;;=> false
(seq? :foo)
;;=> false
Como ya sabes, las listas son secuencias:
(seq? ())
;;=> true
(seq? '(:foo :bar))
;;=> true
Todo lo que obtenga al llamar a seq
o rseq
o las keys
o vals
en una colección no vacía también es una secuencia:
(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
Recuerde que todas las listas son secuencias, pero no todas las secuencias son listas. Mientras que las listas admiten peek
y pop
y count
en tiempo constante, en general, una secuencia no necesita admitir ninguna de esas funciones. Si intentas llamar peek
o pop
en una secuencia que no es compatible con la interfaz de pila de Clojure, obtendrás 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
Si llama al count
en una secuencia que no implementa el count
en un tiempo constante, no obtendrá un error; en su lugar, Clojure recorrerá toda la secuencia hasta que llegue al final, luego devolverá el número de elementos que atravesó. Esto significa que, para secuencias generales, el count
es lineal, no constante, en el tiempo. ¿Puede probar si algo admite el count
tiempo constante usando el counted?
predicado:
(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
Como se mencionó anteriormente, puede usar first
para obtener el primer elemento de una secuencia. Tenga en cuenta que first
llamará a seq
en su argumento, por lo que se puede usar en cualquier cosa "seqable", no solo en secuencias reales:
(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
También como se mencionó anteriormente, puede usar el rest
para obtener una secuencia que contenga todo menos el primer elemento de una secuencia existente. Como first
, llama a la seq
en su argumento. Sin embargo, no llama a la seq
en su resultado! Esto significa que, si llama a rest
en una secuencia que contiene menos de dos elementos, obtendrá back ()
lugar de nil
:
(rest nil)
;;=> ()
(rest '(:foo))
;;=> ()
(rest '(:foo :bar))
;;=> (:bar)
(rest [:foo])
;;=> ()
(rest [:foo :bar])
;;=> (:bar)
(rest {:foo :bar})
;;=> ()
(rest #{:foo})
;;=> ()
Si desea volver a nil
cuando no hay más elementos en una secuencia, puede usar next
lugar de rest
:
(next nil)
;;=> nil
(next '(:foo))
;;=> nil
(next [:foo])
;;=> nil
Puede usar la función cons
para crear una nueva secuencia que devolverá su primer argumento para el first
argumento y su segundo argumento para el rest
:
(cons :foo nil)
;;=> (:foo)
(cons :foo (cons :bar nil))
;;=> (:foo :bar)
Clojure proporciona una gran biblioteca de secuencias con muchas funciones para tratar con secuencias. Lo importante de esta biblioteca es que funciona con cualquier cosa "seqable", no solo con listas. Es por eso que el concepto de una secuencia es tan útil; significa que una sola función, como reduce
, funciona perfectamente en cualquier colección:
(reduce + '(1 2 3))
;;=> 6
(reduce + [1 2 3])
;;=> 6
(reduce + #{1 2 3})
;;=> 6
La otra razón por la que las secuencias son útiles es que, dado que no requieren ninguna implementación particular de first
y rest
, permiten secuencias perezosas cuyos elementos solo se realizan cuando es necesario.
Dada una expresión que crearía una secuencia, puede envolver esa expresión en la macro lazy-seq
para obtener un objeto que actúe como una secuencia, pero solo evaluará esa expresión cuando la función seq
le pida que lo haga, en en qué punto almacenará en caché el resultado de la expresión y reenviará las first
y rest
llamadas al resultado en caché.
Para secuencias finitas, una secuencia perezosa generalmente actúa de la misma manera que una secuencia ansiosa equivalente:
(seq [:foo :bar])
;;=> (:foo :bar)
(lazy-seq [:foo :bar])
;;=> (:foo :bar)
Sin embargo, la diferencia se hace evidente para secuencias infinitas:
(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)
Vectores
Un vector se denota entre corchetes:
[]
;;=> []
[:foo]
;;=> [:foo]
[:foo :bar]
;;=> [:foo :bar]
[1 (+ 1 1) 3]
;;=> [1 2 3]
Además de usar la sintaxis literal, también puede usar la función vector
para construir un vector:
(vector)
;;=> []
(vector :foo)
;;=> [:foo]
(vector :foo :bar)
;;=> [:foo :bar]
(vector 1 (+ 1 1) 3)
;;=> [1 2 3]
¿Puedes probar si algo es un vector usando el vector?
predicado:
(vector? [])
;;=> true
(vector? [:foo :bar])
;;=> true
(vector? nil)
;;=> false
(vector? 42)
;;=> false
(vector? :foo)
;;=> false
conj
agrega elementos al final de un vector:
(conj [] :foo)
;;=> [:foo]
(conj (conj [] :foo) :bar)
;;=> [:foo :bar]
(conj [] :foo :bar)
;;=> [:foo :bar]
count
devuelve el número de elementos, en tiempo constante:
(count [])
;;=> 0
(count (conj [] :foo))
;;=> 1
(count [:foo :bar])
;;=> 2
Puedes obtener el último elemento de un vector usando peek
:
(peek [])
;;=> nil
(peek [:foo])
;;=> :foo
(peek [:foo :bar])
;;=> :bar
Puedes obtener un nuevo vector sin el último elemento usando pop
:
(pop [:foo])
;;=> []
(pop [:foo :bar])
;;=> [:foo]
Tenga en cuenta que si intenta IllegalStateException
un vector vacío, obtendrá una IllegalStateException
:
(pop [])
;; java.lang.IllegalStateException: Can't pop empty vector
A diferencia de las listas, los vectores están indexados. Puede obtener un elemento de un vector por índice en tiempo "constante" usando get
:
(get [:foo :bar] 0)
;;=> :foo
(get [:foo :bar] 1)
;;=> :bar
(get [:foo :bar] -1)
;;=> nil
(get [:foo :bar] 2)
;;=> nil
Además, los vectores en sí mismos son funciones que toman un índice y devuelven el elemento en ese índice:
([:foo :bar] 0)
;;=> :foo
([:foo :bar] 1)
;;=> :bar
Sin embargo, si llama a un vector con un índice no válido, obtendrá una IndexOutOfBoundsException
lugar de nil
:
([:foo :bar] -1)
;; java.lang.IndexOutOfBoundsException:
([:foo :bar] 2)
;; java.lang.IndexOutOfBoundsException:
Puede obtener un nuevo vector con un valor diferente en un índice particular usando assoc
:
(assoc [:foo :bar] 0 42)
;;=> [42 :bar]
(assoc [:foo :bar] 1 42)
;;=> [:foo 42]
Si pasa un índice igual al count
del vector, Clojure agregará el elemento como si hubiera usado conj
. Sin embargo, si pasa un índice que es negativo o mayor que el count
, obtendrá una 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:
Puede obtener una secuencia de los elementos en un vector usando seq
:
(seq [])
;;=> nil
(seq [:foo])
;;=> (:foo)
(seq [:foo :bar])
;;=> (:foo :bar)
Dado que los vectores están indexados, también puede obtener una secuencia invertida de los elementos de un vector utilizando rseq
:
(rseq [])
;;=> nil
(rseq [:foo])
;;=> (:foo)
(rseq [:foo :bar])
;;=> (:bar :foo)
Tenga en cuenta que, aunque todas las listas son secuencias, y las secuencias se muestran de la misma manera que las listas, ¡no todas las secuencias son listas!
'(:foo :bar)
;;=> (:foo :bar)
(seq [:foo :bar])
;;=> (:foo :bar)
(list? '(:foo :bar))
;;=> true
(list? (seq [:foo :bar]))
;;=> false
(list? (rseq [:foo :bar]))
;;=> false
Conjuntos
Al igual que los mapas, los conjuntos son asociativos y desordenados. A diferencia de los mapas, que contienen asignaciones de claves a valores, los conjuntos se asignan esencialmente de las claves a sí mismos.
Un conjunto se denota con llaves, precedido por un octothorpe:
#{}
;;=> #{}
#{:foo}
;;=> #{:foo}
#{:foo :bar}
;;=> #{:bar :foo}
Al igual que con los mapas, el orden en que aparecen los elementos en un conjunto literal no importa:
(= #{:foo :bar} #{:bar :foo})
;;=> true
¿Puedes probar si algo es un conjunto usando el set?
predicado:
(set? #{})
;;=> true
(set? #{:foo})
;;=> true
(set? #{:foo :bar})
;;=> true
(set? nil)
;;=> false
(set? 42)
;;=> false
(set? :foo)
;;=> false
Puede probar si un mapa contiene un ítem dado en tiempo "constante" usando los contains?
predicado:
(contains? #{} :foo)
;;=> false
(contains? #{:foo} :foo)
;;=> true
(contains? #{:foo} :bar)
;;=> false
(contains? #{} nil)
;;=> false
(contains? #{nil} nil)
;;=> true
Además, los propios conjuntos son funciones que toman un elemento y devuelven ese elemento si está presente en el conjunto, o nil
si no lo está:
(#{} :foo)
;;=> nil
(#{:foo} :foo)
;;=> :foo
(#{:foo} :bar)
;;=> nil
(#{} nil)
;;=> nil
(#{nil} nil)
;;=> nil
Puede usar conj
para obtener un conjunto que tenga todos los elementos de un conjunto existente, más un elemento adicional:
(conj #{} :foo)
;;=> #{:foo}
(conj (conj #{} :foo) :bar)
;;=> #{:bar :foo}
(conj #{:foo} :foo)
;;=> #{:foo}
Puede usar disj
para obtener un conjunto que tenga todos los elementos de un conjunto existente, menos un elemento:
(disj #{} :foo)
;;=> #{}
(disj #{:foo} :foo)
;;=> #{}
(disj #{:foo} :bar)
;;=> #{:foo}
(disj #{:foo :bar} :foo)
;;=> #{:bar}
(disj #{:foo :bar} :bar)
;;=> #{:foo}
count
devuelve el número de elementos, en tiempo constante:
(count #{})
;;=> 0
(count (conj #{} :foo))
;;=> 1
(count #{:foo :bar})
;;=> 2
Puede obtener una secuencia de todos los elementos en un conjunto utilizando seq
:
(seq #{})
;;=> nil
(seq #{:foo})
;;=> (:foo)
(seq #{:foo :bar})
;;=> (:bar :foo)
Mapas
A diferencia de la lista, que es una estructura de datos secuencial, y el vector, que es a la vez secuencial y asociativo, el mapa es exclusivamente una estructura de datos asociativa. Un mapa consiste en un conjunto de asignaciones de claves a valores. Todas las claves son únicas, por lo que los mapas admiten la búsqueda en tiempo "constante" de las claves a los valores.
Un mapa se denota con llaves:
{}
;;=> {}
{:foo :bar}
;;=> {:foo :bar}
{:foo :bar :baz :qux}
;;=> {:foo :bar, :baz :qux}
Cada par de dos elementos es un par clave-valor. Entonces, por ejemplo, el primer mapa de arriba no tiene mapeos. El segundo tiene un mapeo, desde la clave :foo
hasta el valor :bar
. El tercero tiene dos asignaciones, una de la clave :foo
al valor :bar
, y una de la clave :baz
al valor :qux
. Los mapas están intrínsecamente desordenados, por lo que el orden en el que aparecen las asignaciones no importa:
(= {:foo :bar :baz :qux}
{:baz :qux :foo :bar})
;;=> true
¿Puedes probar si algo es un mapa usando el map?
predicado:
(map? {})
;;=> true
(map? {:foo :bar})
;;=> true
(map? {:foo :bar :baz :qux})
;;=> true
(map? nil)
;;=> false
(map? 42)
;;=> false
(map? :foo)
;;=> false
¿Puede probar si un mapa contiene una clave dada en tiempo "constante" usando los contains?
predicado:
(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
Puede obtener el valor asociado con una clave 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
Además, los mapas en sí mismos son funciones que toman una clave y devuelven el valor asociado con esa clave:
({: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
Puede obtener una entrada completa del mapa (clave y valor juntos) como un vector de dos elementos 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
Puede extraer la clave o el valor de una entrada de mapa usando key
o val
, respectivamente:
(key (find {:foo :bar} :foo))
;;=> :foo
(val (find {:foo :bar} :foo))
;;=> :bar
Tenga en cuenta que, aunque todas las entradas del mapa de Clojure son vectores, no todos los vectores son entradas del mapa. Si intenta llamar a key
o val
en algo que no sea una entrada de mapa, obtendrá una ClassCastException
:
(key [:foo :bar])
;; java.lang.ClassCastException:
(val [:foo :bar])
;; java.lang.ClassCastException:
¿Puede probar si algo es una entrada de mapa usando la map-entry?
predicado:
(map-entry? (find {:foo :bar} :foo))
;;=> true
(map-entry? [:foo :bar])
;;=> false
Puede usar assoc
para obtener un mapa que tenga todos los mismos pares clave-valor que un mapa existente, con un mapa agregado o modificado:
(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}
Puede usar dissoc
para obtener un mapa que tenga todos los mismos pares clave-valor que un mapa existente, con posiblemente un mapa eliminado:
(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
devuelve el número de mapeos, en tiempo constante:
(count {})
;;=> 0
(count (assoc {} :foo :bar))
;;=> 1
(count {:foo :bar :baz :qux})
;;=> 2
Puede obtener una secuencia de todas las entradas en un mapa usando seq
:
(seq {})
;;=> nil
(seq {:foo :bar})
;;=> ([:foo :bar])
(seq {:foo :bar :baz :qux})
;;=> ([:foo :bar] [:baz :qux])
Nuevamente, los mapas no están ordenados, por lo que el orden de los elementos en una secuencia que se obtiene al llamar a seq
en un mapa no está definido.
Usted puede obtener una secuencia de sólo las teclas o sólo los valores en un mapa utilizando keys
o vals
, respectivamente:
(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 agrega una sintaxis literal para representar de manera más concisa un mapa en el que las claves comparten el mismo espacio de nombres. Tenga en cuenta que el mapa en cualquier caso es idéntico (el mapa no "conoce" el espacio de nombres predeterminado), esto es simplemente una conveniencia sintáctica.
;; 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]"})