【问题标题】:How to order keys in Clojure map? Ideally sort them against a vector of keys如何在 Clojure 映射中排序键?理想情况下,根据键向量对它们进行排序
【发布时间】:2021-08-06 13:43:15
【问题描述】:

我找到了关于如何按值排序地图的不同解决方案,但没有找到关于如何让键以特定顺序出现的解决方案。

我们知道键是自动排序的,不会以插入时的方式显示,但我们可以在之后以某种方式强制它吗?

例如,给定一张地图: (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 对地图矢量执行此操作,但我无法应用这种排序。

有什么想法吗?

(编辑:问题不在于没有维护顺序。实际的问题是如何使映射中的键符合指定的顺序。映射将来自其他地方并在中间,所以无论如何不可能从一开始就以正确的顺序得到它)。

【问题讨论】:

  • @akond 不是真的!他们似乎已经通过在创建过程中使用ordered-map 解决了这个问题,但是我的用例需要通过计算创建地图,并且它们可能以任何顺序到达!所以我必须咨询一个外部向量来对它们进行排序。

标签: clojure


【解决方案1】:

你需要类似以下的东西:

(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 库很有用。单元测试show the code in action

【讨论】:

  • 像魅力一样工作!谢谢!!我有点猜想比较器会是要走的路,但我并没有真正理解它并且害怕尝试!是时候深入研究了。:D
  • 顺便说一句,我需要它来工作,因为我需要将列导出到 CSV 并希望它们以正确的顺序排列!到目前为止也不需要这个!
【解决方案2】:

我想这会让你到达那里

(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

【讨论】:

  • 谢谢!这会以所需的顺序返回一个值向量,结果映射可以通过zipmap!
  • 它实际上不适用于更大范围的键。例如,对于包含 10 个键值对的映射。所以我猜 zipmap 在限制后也会重新排序?
  • 谢谢!正如另一个答案中所建议的那样,比较器方法确实有效。 :)
猜你喜欢
  • 2022-07-29
  • 1970-01-01
  • 2022-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-23
  • 1970-01-01
相关资源
最近更新 更多