如何迭代地图键和值?

sja*_*jac 61 clojure

我有以下想要迭代的地图:

(def db {:classname "com.mysql.jdbc.Driver" 
         :subprotocol "mysql" 
         :subname "//100.100.100.100:3306/clo" 
         :username "usr" :password "pwd"})
Run Code Online (Sandbox Code Playgroud)

我尝试过以下操作,但不是打印键和值一次,而是重复打印键和值作为各种组合:

(doseq [k (keys db) 
        v (vals db)] 
  (println (str k " " v)))
Run Code Online (Sandbox Code Playgroud)

我想出了一个解决方案,但Brian(见下文)更符合逻辑.

(let [k (keys db) v (vals db)] 
  (do (println (apply str (interpose " " (interleave k v))))))
Run Code Online (Sandbox Code Playgroud)

Bri*_*per 92

这是预期的行为. (doseq [x ... y ...])将遍历每个项目中y的每个项目x.

相反,您应该迭代地图本身一次. (seq some-map)将返回一个两项向量的列表,一个用于映射中的每个键/值对.(真的是他们clojure.lang.MapEntry,但表现得像2项向量.)

user> (seq {:foo 1 :bar 2})
([:foo 1] [:bar 2])
Run Code Online (Sandbox Code Playgroud)

doseq可以像其他任何一样遍历那个seq.像Clojure中使用集合的大多数函数一样,在迭代之前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"]
Run Code Online (Sandbox Code Playgroud)

您可以使用keyval,或firstsecond,或nth,或get从这些向量中获取键和值.

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"
Run Code Online (Sandbox Code Playgroud)

更简洁地说,您可以使用解构将每个映射条目的一半绑定到您可以在doseq表单中使用的某些名称.这是惯用的:

user> (doseq [[k v] db] (prn k v))
:subprotocol "mysql"
:username "usr"
:classname "com.mysql.jdbc.Driver"
:subname "//100.100.100.100:3306/clo"
:password "pwd"
Run Code Online (Sandbox Code Playgroud)

  • clojure.core/for是doseq的纯版本:`(for [[kv] {1 2 3 4}](+ kv))=>(3 7)` (13认同)

Mri*_*abh 19

你可以干脆做

(map (fn [[k v]] (prn k) (prn v)) {:a 1 :b 2})

结果是:

:a
1
:b
2
Run Code Online (Sandbox Code Playgroud)

这是你在找什么?


kot*_*rak 5

只是Brian回答的一小段内容:

您的原始版本也可以编写如下。

(doseq [[k v] (map vector (keys db) (vals db))]
  (println (str k " " v)))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这显然是愚蠢的。但总的来说,这也适用于不相关的输入序列,这些输入序列并非源于同一图。


rdg*_*dgd 5

如果您想解决的不仅仅是打印值(副作用),还不清楚,如果这就是您想要的,那么我认为doseq上面的解决方案将是最惯用的。如果您想对映射的键和值进行一些操作并返回相同类型的数据结构,那么您应该查看reduce-kv,您可以在此处找到相关文档

reduce,reduce-kv接受一个函数、一个起始值/累加器和一些数据,但在这种情况下,数据是一个映射而不是一个序列。该函数传递了三个参数:累加器、当前键和当前值。如果您确实想做一些数据转换并返回一些数据,这对我来说似乎是适合这项工作的工具。