Search code examples
clojureclojurescript

ClojureScript zipmap tricks me or what?


I use Clojurescript to develop webbrowser-games. (Actually a friend of mine teaches me, we started only a few weeks ago).

I wanted to generate a map in which keys are vectors and values are numbers. For e.g.: {[0 0] 0, [0 1] 1, [0 2] 2, ...}.

I used this formula:

 (defn oxo [x y]
   (zipmap (map vec (combi/cartesian-product (range 0 x) (range 0 y))) (range (* x y))))

(where combi/ refers to clojure.math.combinatorics).

When it generates the map, key-value pairs are ok, but they are in a random order, like:

{[0 1] 1, [6 8] 68, [6 9] 69, [5 7] 57, ...}

What went wrong after using zipmap and how can i fix it?


Solution

  • Clojure maps aren't guaranteed to have ordered/sorted keys. If you want to ensure the keys are sorted, use a sorted-map:

    (into (sorted-map) (oxo 10 10))
    =>
    {[0 0] 0,
     [0 1] 1,
     [0 2] 2,
     [0 3] 3,
     [0 4] 4,
     [0 5] 5,
    ...
    

    If your map has fewer than 9 keys then insertion order is preserved because the underlying data structure is different depending on the number of keys:

    1. clojure.lang.PersistentArrayMap for <9 keys
    2. clojure.lang.PersistentHashMap otherwise.

    array-map produces a clojure.lang.PersistentArrayMap and sorted-map produces a clojure.lang.PersistentTreeMap. Note that associng onto an array map may produce a hash map, but associng on to a sorted map still produces a sorted map.