我找到了关于如何按值排序地图的不同解决方案,但没有找到关于如何让键以特定顺序出现的解决方案。
我们知道键是自动排序的,不会以插入的方式出现,但我们可以在之后以某种方式强制它吗?
例如,给定一张地图:
(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}
使用我最喜欢的模板项目.
但是,请记住,排序后的地图只会影响它们在终端上的打印方式。对于所有其他用途,使用排序地图没有任何好处(维护它们可能会很痛苦)。
另请参阅此文档列表,尤其是 Clojure CheatSheet。
如果您只需要将一些地图导出为 CSV,您可能会发现 tupelo.csv 库很有用。单元测试显示代码的运行。
还请考虑使用以下方法获取地图,其中的键按照向量中的描述进行排序:
(defn get-map-sorted-by-order
[some-map keys-order]
(into (sorted-map-by (fn [first-key second-key]
(< (.indexOf keys-order first-key)
(.indexOf keys-order second-key))))
some-map))
它使用Java的
.indexOf
。不过,我觉得很方便。
(get-map-sorted-by-order
{:hello "Hello", :world "World", :comma-space ", ", :exclamation "!"}
[:hello :comma-space :world :exclamation])
导致以下结果:
{:hello "Hello", :comma-space ", ", :world "World", :exclamation "!"}