如何在Clojure中迭代映射键和值?
我有以下要迭代的映射:如何在Clojure中迭代映射键和值?,clojure,Clojure,我有以下要迭代的映射: (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
(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)))
我提出了一个解决方案,但Brian的(见下文)更符合逻辑
(let [k (keys db) v (vals db)]
(do (println (apply str (interpose " " (interleave k v))))))
这是预期的行为
(doseq[x…y…])
将针对x
中的每个项目迭代y
相反,您应该在映射本身上迭代一次<代码>(seq some map)将返回两个项向量的列表,每个项向量对应于映射中的每个键/值对。(实际上它们是clojure.lang.MapEntry
,但其行为类似于两项向量。)
doseq
可以像其他任何序列一样迭代该序列。与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"]
您可以使用key
和val
,或first
和second
,或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"
更简单地说,您可以使用destructuring将地图条目的每一半绑定到可以在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"
只是对Brian的答案的简短补充: 您的原始版本也可以写如下
(doseq [[k v] (map vector (keys db) (vals db))]
(println (str k " " v)))
在这种情况下,这显然是愚蠢的。但一般来说,这也适用于不相关的输入序列,它们不是来自同一映射。您可以简单地执行
(map(fn[[kv]](prnk)(prnv)){:a1:b2}
结果是:
:a
1
:b
2
这就是你想要的吗?不完全清楚你是否在试图解决打印值(副作用)以外的问题,如果这就是你想要的,那么我认为上面的
doseq
解决方案将是最惯用的。如果您想对映射的键和值执行一些操作,并返回相同类型的数据结构,那么您应该查看reduce kv
,您可以找到相应的文档
与
reduce
类似,reduce kv
接受一个函数、一个起始值/累加器和一些数据,但在这种情况下,数据是一个映射而不是一个序列。该函数通过三个参数:累加器、当前键和当前值。如果您确实想进行一些数据转换并返回一些数据,这对我来说似乎是适合这项工作的工具。感谢您的解释和示例;他们非常有帮助。据我所知,作为后续行动,doseq
适用于存在“副作用”的情况。如果我不想要任何“副作用”,比如打印,我该怎么办?clojure.core/for是doseq的纯版本:(对于[[kv]{1234}](+kv))=>(37)
与其说“想要”副作用,不如说“想要”副作用“需要”副作用。doseq
和for
之间的区别是:……1)for
增加了懒散性:for
不会在迭代中生成下一个元素,直到“调用代码”明确需要该元素“。另一方面,doseq
将迭代元素直到耗尽:如果有副作用需要执行,则应尽快执行(即在不间断循环中)
:a
1
:b
2