如何在 Clojure 地图中订购钥匙?理想情况下,根据键向量对它们进行排序
How to order keys in Clojure map? Ideally sort them against a vector of keys
我找到了关于如何按值对地图进行排序的不同解决方案,但是 none 关于如何让键以特定顺序出现的问题。
我们知道键是自动排序的,不会以它们插入的方式出现,但我们可以在之后以某种方式强制它吗?
例如,给定一张地图:
(def my-map {:one 1 :two 2 :three 3 :four 4 :five 5})
,
我想更改它们的显示顺序。
所需的键在向量中
(def sorted-keys-here [:four :three :five :two :one])
这样,我希望地图在 sort-fn 应用后显示为:
=> {:four 4 :three 3 :five 5 :two 2 :one 1}
密钥始终是固定的,我会使用 map
对地图矢量执行此操作,但我无法应用这种类型。
有什么想法吗?
(编辑:问题不在于顺序没有维护。实际问题是如何使映射中的键符合指定顺序。映射将来自其他地方并正在经历转换在中间,所以无论如何都不可能从一开始就以正确的顺序得到它。
我想这会让你到达那里
(def my-map {:one 1 :two 2 :three 3 :four 4 :five 5})
(map my-map [:four :three :five :two :one]) ;
您可以即时放置您的通用键向量
(def vector-seq [:two :one])
(map my-map vector-seq) ; this will return list
(mapv my-map vector-seq) ; this will return vector
或者你可以做的是“加权”输入向量
(let [my-map {:one 1 :two 2 :three 3 :four 4 :five 5}
vector-seq [:five :three :two :four :one]
weight (apply hash-map (interleave vector-seq (range (count vector-seq))))]
(into
(sorted-map-by
(fn [key1 key2]
(> (get weight key2)
(get weight key1))))
my-map ))
这将产生 sorted-map
序列为 vector-seq
您需要如下内容:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [keys-ordered [:one :two :three :four :five :six]
keys->idx (zipmap keys-ordered (range))
order-fn (fn [x y] (< (keys->idx x) (keys->idx y))) ; a comparitor
m {:one 1
:two 2
:three 3
:four 4
:five 5
:six 6}
m-sorted-norm (into (sorted-map) m)
m-sorted-custom (into (sorted-map-by order-fn) m) ]
(spyx-pretty m-sorted-norm)
(spyx-pretty m-sorted-custom)
))
这将产生:
m-sorted-norm =>
{:five 5, :four 4, :one 1, :six 6, :three 3, :two 2}
m-sorted-custom =>
{:one 1, :two 2, :three 3, :four 4, :five 5, :six 6}
使用 my favorite template project.
但是,请记住,经过排序的地图只会影响它们在终端上的打印方式。对于所有其他用途,使用排序映射没有任何好处(维护它们可能会很痛苦)。
另请参阅 this list of documentation,尤其是 Clojure CheatSheet。
更新
如果您只需要将一些地图导出为 CSV,您可能会发现 tupelo.csv library useful. The unit tests show the code in action。
我找到了关于如何按值对地图进行排序的不同解决方案,但是 none 关于如何让键以特定顺序出现的问题。
我们知道键是自动排序的,不会以它们插入的方式出现,但我们可以在之后以某种方式强制它吗?
例如,给定一张地图:
(def my-map {:one 1 :two 2 :three 3 :four 4 :five 5})
,
我想更改它们的显示顺序。
所需的键在向量中
(def sorted-keys-here [:four :three :five :two :one])
这样,我希望地图在 sort-fn 应用后显示为:
=> {:four 4 :three 3 :five 5 :two 2 :one 1}
密钥始终是固定的,我会使用 map
对地图矢量执行此操作,但我无法应用这种类型。
有什么想法吗?
(编辑:问题不在于顺序没有维护。实际问题是如何使映射中的键符合指定顺序。映射将来自其他地方并正在经历转换在中间,所以无论如何都不可能从一开始就以正确的顺序得到它。
我想这会让你到达那里
(def my-map {:one 1 :two 2 :three 3 :four 4 :five 5})
(map my-map [:four :three :five :two :one]) ;
您可以即时放置您的通用键向量
(def vector-seq [:two :one])
(map my-map vector-seq) ; this will return list
(mapv my-map vector-seq) ; this will return vector
或者你可以做的是“加权”输入向量
(let [my-map {:one 1 :two 2 :three 3 :four 4 :five 5}
vector-seq [:five :three :two :four :one]
weight (apply hash-map (interleave vector-seq (range (count vector-seq))))]
(into
(sorted-map-by
(fn [key1 key2]
(> (get weight key2)
(get weight key1))))
my-map ))
这将产生 sorted-map
序列为 vector-seq
您需要如下内容:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(let [keys-ordered [:one :two :three :four :five :six]
keys->idx (zipmap keys-ordered (range))
order-fn (fn [x y] (< (keys->idx x) (keys->idx y))) ; a comparitor
m {:one 1
:two 2
:three 3
:four 4
:five 5
:six 6}
m-sorted-norm (into (sorted-map) m)
m-sorted-custom (into (sorted-map-by order-fn) m) ]
(spyx-pretty m-sorted-norm)
(spyx-pretty m-sorted-custom)
))
这将产生:
m-sorted-norm =>
{:five 5, :four 4, :one 1, :six 6, :three 3, :two 2}
m-sorted-custom =>
{:one 1, :two 2, :three 3, :four 4, :five 5, :six 6}
使用 my favorite template project.
但是,请记住,经过排序的地图只会影响它们在终端上的打印方式。对于所有其他用途,使用排序映射没有任何好处(维护它们可能会很痛苦)。
另请参阅 this list of documentation,尤其是 Clojure CheatSheet。
更新
如果您只需要将一些地图导出为 CSV,您可能会发现 tupelo.csv library useful. The unit tests show the code in action。