Search code examples
sortingclojureclojurescript

Clojure: into {} doesn't preserve sort order


I have a nested map which is structured like this (Clojurescript):

{"6841"
 {"primaryTitle" "First name",
  "secondaryTitle" "last name"},
 "7944"
 {"primaryTitle" "Test 2 first name",
  "secondaryTitle" "Test 2 last name"}}

I then proceed to sort the map with the keys inside the nested map, like this:

(defn compare-title [x y]
  (compare [(get (second x) "primaryTitle") (get (second x) "secondaryTitle")]
           [(get (second y) "primaryTitle") (get (second y) "secondaryTitle")]))

(sort compare-title @loaded-assets)

So far the sorting works fine, but since sort function return the data structure like this:

    ["6841"
     {"primaryTitle" "First name",
      "secondaryTitle" "last name"}],
    ["7944"
     {"primaryTitle" "Test 2 first name",
      "secondaryTitle" "Test 2 last name"}]}

I have to use into {} to transform the map back to the initial structure:

(into {} (sort compare-title my-map))

But this completely reverses the sorting which is made by sort. I've tried to replace into {} with:

  1. flatten (which transforms this into list)
  2. apply hash-map (which behaves similar to into {})
  3. reduce hash-map (which preserves the order, but deeply nests each map into each other)

So, is it possible to sort the map while preserving the structure? Or how to transform back to the above original structure while preserving the sorted structure returned by sort?


Solution

  • You can use priority-map

    (use 'clojure.data.priority-map)
    
    (defn compare-title [x y]
      (compare [(get x "primaryTitle") (get x "secondaryTitle")]
               [(get y "primaryTitle") (get y "secondaryTitle")]))
    
    (apply priority-map-by compare-title
           ["7944"
            {"primaryTitle"   "Test 2 first name"
             "secondaryTitle" "Test 2 last name"}
            "6841"
            {"primaryTitle"   "First name"
             "secondaryTitle" "last name"}])
    
    ;; => {"6841" {"primaryTitle" "First name", "secondaryTitle" "last name"}, "7944" {"primaryTitle" "Test 2 first name", "secondaryTitle" "Test 2 last name"}}