Clojure:into {} 不保留排序顺序
Clojure: into {} doesn't preserve sort order
我有一个嵌套映射,其结构如下 (Clojurescript):
{"6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}}
然后我继续使用嵌套映射中的键对映射进行排序,如下所示:
(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)
到目前为止排序工作正常,但由于排序函数 return 数据结构如下:
["6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"}],
["7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}]}
我必须使用 into {}
将地图转换回初始结构:
(into {} (sort compare-title my-map))
但这完全颠倒了排序的排序。我尝试将 into {}
替换为:
flatten
(将其转换为列表)
apply hash-map
(其行为类似于 into {}
)
reduce hash-map
(保留顺序,但将每个映射深深地嵌套在一起)
那么,是否可以在保留结构的同时对地图进行排序?
或者如何在保留 return 由 sort
编辑的排序结构的同时转换回上述原始结构?
如前所述,地图不能按值排序。它们可以按键排序。这是最简单的方法with some helper functions:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def data
{"6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}})
(def data-sorted ; maybe use `postwalk` instead
(->sorted-map
(map-vals data ->sorted-map)))
(dotest
(is= data-sorted
{"6841" {"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944" {"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}}))
如果您想按 primary/secondary 标题排序,请将这 2 项放在 "sort key" 中,然后基于此排序:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def all-data {"7944" {"primaryTitle" "Test 2 first name"
"secondaryTitle" "Test 2 last name"}
"6841" {"primaryTitle" "First name"
"secondaryTitle" "last name"}})
(dotest
(let [data-keyed (forv [entry all-data]
(let [[id title-map] entry]
{:sort-key [(grab "primaryTitle" title-map)
(grab "secondaryTitle" title-map)]
:id id}))
data-sorted (vec (sort-by :sort-key data-keyed))]
(is= (spy-pretty data-keyed)
[{:sort-key ["Test 2 first name" "Test 2 last name"] :id "7944"}
{:sort-key ["First name" "last name"] :id "6841"}])
(is= (spy-pretty data-sorted)
[{:sort-key ["First name" "last name"] :id "6841"}
{:sort-key ["Test 2 first name" "Test 2 last name"] :id "7944"}])))
您可以使用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"}}
我有一个嵌套映射,其结构如下 (Clojurescript):
{"6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}}
然后我继续使用嵌套映射中的键对映射进行排序,如下所示:
(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)
到目前为止排序工作正常,但由于排序函数 return 数据结构如下:
["6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"}],
["7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}]}
我必须使用 into {}
将地图转换回初始结构:
(into {} (sort compare-title my-map))
但这完全颠倒了排序的排序。我尝试将 into {}
替换为:
flatten
(将其转换为列表)apply hash-map
(其行为类似于into {}
)reduce hash-map
(保留顺序,但将每个映射深深地嵌套在一起)
那么,是否可以在保留结构的同时对地图进行排序?
或者如何在保留 return 由 sort
编辑的排序结构的同时转换回上述原始结构?
如前所述,地图不能按值排序。它们可以按键排序。这是最简单的方法with some helper functions:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def data
{"6841"
{"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944"
{"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}})
(def data-sorted ; maybe use `postwalk` instead
(->sorted-map
(map-vals data ->sorted-map)))
(dotest
(is= data-sorted
{"6841" {"primaryTitle" "First name",
"secondaryTitle" "last name"},
"7944" {"primaryTitle" "Test 2 first name",
"secondaryTitle" "Test 2 last name"}}))
如果您想按 primary/secondary 标题排序,请将这 2 项放在 "sort key" 中,然后基于此排序:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def all-data {"7944" {"primaryTitle" "Test 2 first name"
"secondaryTitle" "Test 2 last name"}
"6841" {"primaryTitle" "First name"
"secondaryTitle" "last name"}})
(dotest
(let [data-keyed (forv [entry all-data]
(let [[id title-map] entry]
{:sort-key [(grab "primaryTitle" title-map)
(grab "secondaryTitle" title-map)]
:id id}))
data-sorted (vec (sort-by :sort-key data-keyed))]
(is= (spy-pretty data-keyed)
[{:sort-key ["Test 2 first name" "Test 2 last name"] :id "7944"}
{:sort-key ["First name" "last name"] :id "6841"}])
(is= (spy-pretty data-sorted)
[{:sort-key ["First name" "last name"] :id "6841"}
{:sort-key ["Test 2 first name" "Test 2 last name"] :id "7944"}])))
您可以使用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"}}