如何遍历映射键和值?
我有我想要迭代的以下映射:
(def db {:classname "com.mysql.jdbc.Driver" :subprotocol "mysql" :subname "//100.100.100.100:3306/clo" :username "usr" :password "pwd"})
我尝试了以下,而不是打印键和值一次 ,它反复打印键和值作为各种组合:
(doseq [k (keys db) v (vals db)] (println (str k " " v)))
我提出了一个解决scheme,但布赖恩(见下文)更合乎逻辑。
(let [k (keys db) v (vals db)] (do (println (apply str (interpose " " (interleave kv))))))
这是预期的行为。 (doseq [x ... y ...])
将遍历y
中每个项目中的每个项目。
相反,你应该迭代一次地图本身。 (seq some-map)
将返回两个项目向量的列表,其中一个用于映射中的每个键/值对。 (真的,他们是clojure.lang.MapEntry
,但行为像2项vector。)
user> (seq {:foo 1 :bar 2}) ([:foo 1] [:bar 2])
doseq
可以像其他任何一样迭代该seq。 与Clojure中与集合doseq
工作的大多数函数一样, doseq
在迭代之前会在集合中内部调用seq
。 所以你可以简单地这样做:
user> (doseq [keyval db] (prn keyval)) [:subprotocol "mysql"] [:username "usr"] [:classname "com.mysql.jdbc.Driver"] [:subname "//100.100.100.100:3306/clo"] [:password "pwd"]
您可以使用key
和val
,或者first
, second
或nth
,或者从这些向量中获取键和值。
user> (doseq [keyval db] (prn (key keyval) (val keyval))) :subprotocol "mysql" :username "usr" :classname "com.mysql.jdbc.Driver" :subname "//100.100.100.100:3306/clo" :password "pwd"
更简洁地说,您可以使用解构来将每个映射条目的一半绑定到您可以在doseq
表单中使用的某些名称。 这是惯用的:
user> (doseq [[kv] db] (prn kv)) :subprotocol "mysql" :username "usr" :classname "com.mysql.jdbc.Driver" :subname "//100.100.100.100:3306/clo" :password "pwd"
你可以简单的做
(map (fn [[kv]] (prn k) (prn v)) {:a 1 :b 2})
结果是:
:a 1 :b 2
这是你在找什么?
Brian的答案只是一个简短的补充:
你的原始版本也可以写成如下。
(doseq [[kv] (map vector (keys db) (vals db))] (println (str k " " v)))
在这种情况下,这显然是愚蠢的。 但总的来说,这也适用于不相关的input序列,这些input序列不是来自同一个映射。