ClojureDocs

Nav

Namespaces

sorted-map

clojure.core

Available since 1.0 (source)
  • (sorted-map & keyvals)
keyval => key val
Returns a new sorted map with supplied mappings.  If any keys are
equal, they are handled as if by repeated uses of assoc.
8 Examples
;; Sorted maps are sorted by their keys, not their values.

user=> (sorted-map :z 0, :a 28, :b 35)
{:a 28, :b 35, :z 0}
user=> (into (sorted-map) {:a 2 :b 1})
{:a 2, :b 1}

;; (sorted-map ...) is equivalent in behavior to (sorted-map-by compare ...)
;; where compare is Clojure's default comparator function clojure.core/compare

;; For a map sorted by values, see the priority-map data structure:
;; https://github.com/clojure/data.priority-map

;; For a map sorted by the order that key/value pairs were added,
;; see array-map

;; Another sorted map variant is the ordering-map:
;; https://github.com/clj-commons/useful/blob/dc5cdebf8983a2e2ea24ec8951fbb4dfb037da45/src/flatland/useful/map.clj#L243-L245

;; If you deal with many large maps where the keys are all integers, and
;; want a faster data structure for those, see int-map:
;; https://github.com/clojure/data.int-map
; 'seq' can be used to turn a map into a list of vectors
; notice how the list is built in the sorted order as with vectors.
(seq (into (sorted-map) {:key1 "value1" :key2 "value2"}))
;;=> ([:key1 "value1"] [:key2 "value2"])
; sorting on integer keys
; also notice how each pair becomes a `MapEntry` ('key' 'val')
(into (sorted-map) [[23 :x] [17 :y]])
;;=> {17 :y, 23 :x}
;; clojure doesn't have a `sorted-map?` function to distinguish a sorted-map
;; from a regular map. use `instance?`:
(def unremarkable-map {:k1 "v1" :k2 "v2"})
(def very-remarkable-map (into (sorted-map) unremarkable-map))
(instance? clojure.lang.PersistentTreeMap unremarkable-map)
;;=> false
(instance? clojure.lang.PersistentTreeMap very-remarkable-map)
;;=> true

;; This works because:
(type unremarkable-map)
;;=> clojure.lang.PersistentArrayMap (PersistentHashMap if many key-val-pairs)
(type very-remarkable-map)
;;=> clojure.lang.PersistentTreeMap

;; Clojure does have a `sorted?` predicate so you could define `sorted-map?`
(def sorted-map? (every-pred map? sorted?))
;; Sort hash map by it's keys
(def data {"k" 11 "z" 12 "a" 13 "d" 14 })

(into (sorted-map) (sort-by first (seq data)))

;;=> {"a" 13, "d" 14, "k" 11, "z" 12}
;; (from previous comment) clojure doesn't have a `sorted-map?` function to distinguish a sorted-map
;; from a regular map. use `instance?`:

;;You can indeed check if the sorted-map is an instance of a clojure.lang.PersistentTreeMap but it won't work for cljs/cljc code.

;; +1 for the use of `map?` and `sorted?` 

(and (sorted? m) (map? m))
;; In ClojureScript, no exception gets thrown if you pass it a map
;; rather than keyvals, leading to potentially unexpected data

;; In Clojure (1.11.1):

(sorted-map {:b 1 :a 2})

;; Execution error (IllegalArgumentException) at user/eval1 (REPL:1).
;; No value supplied for key: {:b 1, :a 2}

;; In ClojureScript (1.8.40):

(sorted-map {:b 1 :a 2})

;; => {{:b 1, :a 2} nil}

;; ^ is a sorted map, containing the passed in map as the key, with nil as the value

;; What you probably want instead, as illustrated by the other examples:

(into (sorted-map) {:b 1 :a 2})

;; => {:a 2, :b 1}
;; sorted-map requires that all keys are of the same type, otherwise the default
;; clojure compare will throw a ClassCastException when attempt to get/insert

(sorted-map :b "bar" :a "foo")
;;=> {:a "foo" :b "bar"}

(sorted-map "b" "bar" :a "foo")
;;=> Execution error (ClassCastException) at user/eval1 (REPL:1).
;;=> class java.lang.String cannot be cast to class clojure.lang.Keyword

;; In addition, if you attempt to access keys of a different type from those
;; that exist in the sorted-map you'll also get a ClassCastException from the
;; default compare fn

(def m (sorted-map :b "bar" :a "foo"))

(get m :a) ;;=> "foo"

(get m :b) ;;=> "bar"

(get m "a")
;;=> Execution error (ClassCastException) at user/eval1 (REPL:1).
;; class java.lang.String cannot be cast to class clojure.lang.Keyword

;; If you find yourself in a situation where you cannot guarantee the type of
;; the key to lookup, you will need to write a custom compare fn and use
;; sorted-map-by to have the same behavior as PersistentArrayMap and avoid an
;; exception being thrown.

(def p (sorted-map-by (fn [a b] (try (compare a b) (catch Exception _ 1)))
                      :b "bar"
                      :a "foo"))

(get p :a) ;;=> "foo"

(get p "a") ;;=> nil
See Also

keyval => key val Returns a new sorted map with supplied mappings, using the supplied comparator...

Added by gstamp

sc must be a sorted collection, test(s) one of <, <=, > or >=. Returns a seq of those entries with...

Added by Chouser

sc must be a sorted collection, test(s) one of <, <=, > or >=. Returns a reverse seq of those entr...

Added by Chouser

Returns a new sorted set with supplied keys. Any equal keys are handled as if by repeated uses of...

Added by Chouser

Constructs an array-map. If any keys are equal, they are handled as if by repeated uses of assoc.

Added by ryo

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

Added by ryo

Returns true if coll implements Sorted

Added by miner

Comparator. Returns a negative number, zero, or a positive number when x is logically 'less than',...

Added by jafingerhut
1 Note
    By , created 3.1 years ago, updated 3.1 years ago

    If transient operations are needed for sorted-map, use data.avl instead of this built-in one.