Clojure 中哈希映射的解构和处理向量

Destructure and process vector of hash-maps in Clojure

我有一个散列映射向量,如下所示:

(def my-maps [{:a 1} {:b 2}])

我想遍历每个哈希图,在循环中为键和值赋予一个更有意义的名称,然后根据其键以不同方式处理每个哈希图。

事不宜迟,这是我最好的尝试:

(for [m my-maps]
  (let [my-key-name (key m) my-val-name (val m)]
    (case my-key-name
      :a (println "Found key :a with value " my-val-name)
      :b (println "Found key :b with value " my-val-name))))

但是,这种方法会产生一个相当神秘的错误:

; Error printing return value (ClassCastException) at clojure.core/key (core.clj:1569).
; class clojure.lang.PersistentArrayMap cannot be cast to class java.util.Map$Entry (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; java.util.Map$Entry is in module java.base of loader 'bootstrap')

我做错了什么?

你可以在里面解构for (or use doseq):

(for [[[k v] & _] [{:a 1} {:b 2}]]
  (println "Found key" k "with value" v))

Found key :a with value 1
Found key :b with value 2
=> (nil nil)

为了清楚起见,这里有一个更笼统的答案,分为各个步骤:

  (let [my-maps [{:a 1} {:b 2 :c 3}]]
    (doseq [curr-map my-maps]
      (newline)
      (println "curr-map=" curr-map)
      (let [map-entries (seq curr-map)]
        (println "map-entries=" map-entries)
        (doseq [curr-me map-entries]
          (let [[k v] curr-me]
            (println "  curr-me=" curr-me "  k=" k  "  v=" v))))))

有结果

curr-map= {:a 1}
map-entries= ([:a 1])
  curr-me= [:a 1]   k= :a   v= 1

curr-map= {:b 2, :c 3}
map-entries= ([:b 2] [:c 3])
  curr-me= [:b 2]   k= :b   v= 2
  curr-me= [:c 3]   k= :c   v= 3

Clojure 中的 MapEntry 对象可以被视为二元向量(通过 first & second 访问)或作为 MapEntry 通过keyval 函数。解构形式:

(let [[k v] curr-me] 

MapEntry 对象 curr-me 视为一个序列,并将前 2 个元素提取到 kv 中。尽管它像矢量一样打印(例如 [:a 1]),但它确实具有 clojure.lang.MapEntry.

类型

原始答案的 for 表达式中的解构语法 & _ 是“rest args”解构。它导致第一个对象之后的所有 MapEntry 个对象的序列被分配给变量 _,然后在其余代码中被忽略。