问题
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?
回答1:
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:
clojure.lang.PersistentArrayMap
for <9 keysclojure.lang.PersistentHashMap
otherwise.
array-map
produces a clojure.lang.PersistentArrayMap
and sorted-map
produces a clojure.lang.PersistentTreeMap
. Note that assoc
ing onto an array map may produce a hash map, but assoc
ing on to a sorted map still produces a sorted map.
回答2:
zipmap
produces a hash-map where order of the keys is not guaranteed.
If you want ordered keys you can use either sorted-map
or array-map
.
回答3:
As far as my knowledge goes, you should not rely on Map/Hash/Dictionary for ordering in any languages.
If the order is important but you don't need O(1) lookup performance of the map, a vector of vector pairs is a good option for you.
(defn oxo [x y]
(mapv vector (map vec (combi/cartesian-product (range 0 x) (range 0 y))) (range (* x y))))
You will get something like this.
=> (oxo 10 10)
[[[0 0] 0] [[0 1] 1] [[0 2] 2] [[0 3] 3] [[0 4] 4] [[0 5] 5] ...]
来源:https://stackoverflow.com/questions/48652038/clojurescript-zipmap-tricks-me-or-what