ClojureDocs

Nav

Namespaces

array-map

clojure.core

Available since 1.0 (source)
  • (array-map)
  • (array-map & keyvals)
Constructs an array-map. If any keys are equal, they are handled as
if by repeated uses of assoc.
5 Examples
user=> (array-map [1 2] [3 4 5])
{[1 2] [3 4 5]}
user=> (array-map :a 10)
{:a 10}

user=> (array-map :a 10 :b 20)
{:a 10 :b 20}

user=> (apply array-map [:a 10 :b 20 :c 30])
{:a 10 :b 20 :c 30}

user=> (apply assoc {} [:a 10 :b 20 :c 30]) ;same result using assoc
{:a 10 :b 20 :c 30}
user=> (keys (assoc (array-map :foo 10 :bar 20) :baz 30))
(:baz :foo :bar)
; baz is first; :foo and :bar follow the order given to array-map


;; My results have consistently been different from what's listed above.
user=> (keys (assoc (array-map :foo 10 :bar 20) :baz 30))
; => (:foo :bar :baz)
user=> (assoc (array-map :foo 10 :bar 20) :baz 30)
; => {:foo 10, :bar 20, :baz 30}
user=> *clojure-version*
; => {:major 1, :minor 8, :incremental 0, :qualifier nil}
;; As long as I have an array map, new items get added to the end, not
;; the beginning.
;; Sometimes Clojure will automatically choose between a hash map and
;; an array map.  What's the rule?  Let's try a few experiments.

;; Start with a quick way to make a map with N items.
user=> (defn make-map [count] (zipmap (range count) (range count)))
;; => #'user/make-map
user=> (make-map 3)
;; => {0 0, 1 1, 2 2}

;; Try a few maps.  The cutoff seems to be 9.5.  If you have fewer than
;; 9.5 items you get an array map.  If you have more than 9.5 items you
;; get a hash map.
user=> (type (make-map 8))
;; => clojure.lang.PersistentArrayMap
user=> (type (make-map 9))
;; => clojure.lang.PersistentArrayMap
user=> (type (make-map 10))
;; => clojure.lang.PersistentHashMap
user=> (type (make-map 11))
;; => clojure.lang.PersistentHashMap

;; Using assoc we get similar results.  9 or fewer items yields an array
;; map.  10 or more yields a hash map.
user=> (type (assoc (make-map 9) :x 1))  ; 10 items -> hash map.
;; => clojure.lang.PersistentHashMap
user=> (type (assoc (make-map 8) :x 1))  ; 9 items -> array map.
;; => clojure.lang.PersistentArrayMap
user=> (type (assoc (make-map 8) :x 1 :y 2))  ; 10 items -> hash map.
;; => clojure.lang.PersistentHashMap
user=> (type (assoc (assoc (make-map 8) :x 1) :y 2))  ; 10 items -> hash map.
;; => clojure.lang.PersistentHashMap

;; But when we use { and } to create a map, the cutoff seems to move to 8.5.
;; A map with 9 items created with assoc or zipmap would be an array map,
;; but a map with 9 items created by { } is a hash map.
user=> (type {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7})  ; 8 items -> array map.
;; => clojure.lang.PersistentArrayMap
user=> (type {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7, 8 8})  ; 9 items -> hash
;; => clojure.lang.PersistentHashMap

;; Calling dissoc on an array map always yields an array map, regardless of
;; the size of the map.
;; Let's start by making a large array map then remove a few items.  This will
;; give us array maps larger than you could create with assoc.
user=> (def array20 (apply array-map (range 40)))
;; => #'user/array20
user=> (type array20)
;; => clojure.lang.PersistentArrayMap
user=> (type (dissoc array20 6))
;; => clojure.lang.PersistentArrayMap
user=> (count (dissoc array20 6))
;; => 19
user=> (type (dissoc array20 6 2))
;; => clojure.lang.PersistentArrayMap
user=> (count (dissoc array20 6 2))
;; => 18

;; Calling dissoc on a hash map always yields another hash map, regardless
;; of the size of the map.
;; Let's start by making a large hash map then remove a lot of items.  This
;; will give us hash maps smaller than you could create with assoc.
user=> (type (make-map 40))
;; => clojure.lang.PersistentHashMap
user=> (type (apply dissoc (make-map 40) (range 1 80)))
;; => clojure.lang.PersistentHashMap
user=> (count (apply dissoc (make-map 40) (range 1 80)))
;; => 1
user=> (apply dissoc (make-map 40) (range 1 80))
;; => {0 0}
user=> (type (apply dissoc (make-map 40) (range 0 80)))
;; => clojure.lang.PersistentHashMap
user=> (count (apply dissoc (make-map 40) (range 0 80)))
;; => 0
user=> (apply dissoc (make-map 40) (range 0 80))
;; => {}
;; Maybe you generated a sequence of kv pairs
(def kvs [[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8] [:i 9]])

;; A naïve approach to putting into an array-map…
(into (array-map) kvs)
;; => {:e 5, :g 7, :c 3, :h 8, :b 2, :d 4, :f 6, :i 9, :a 1}
;; …loses order
(type *1)
;; => clojure.lang.PersistentHashMap

;; This approach…
(apply array-map (sequence cat kvs))
;; => {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7, :h 8, :i 9}
;; …preserves order
(type *1)
;; => clojure.lang.PersistentArrayMap
See Also

assoc[iate]. When applied to a map, returns a new map of the same (hashed/sorted) type, that con...

Added by kumarshantanu

keyval => key val Returns a new hash map with supplied mappings. If any keys are equal, they ar...

Added by ryo

keyval => key val Returns a new sorted map with supplied mappings. If any keys are equal, they ...

Added by ryo
2 Notes
    By , created 14.7 years ago

    The definition is kind of short, IMO. More descriptively, array-map creates a mapping with arrays being the keys and the values. It doesn't seem like array-map cares whether or not the keys/values are arrays, although it doesn't seem to like sequences.

    By , created 14.0 years ago

    An array-map maintains the insertion order of the keys. Look up is linear, which is not a problem for small maps (say less than 10 keys). If your map is large, you should use hash-map instead.

    When you assoc onto an existing array-map, the result is a new array-map with the new key as the first key. The rest of the keys are in the same order as the original. Functions such as seq and keys will respect the key order.

    Note that assoc will decide to return a hash-map if the result is too big to be efficient.