如何迭代地图键和值?

时间:2011-07-13 21:27:47

标签: 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 (vals db)] 
  (println (str k " " v)))

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

(let [k (keys db) v (vals db)] 
  (do (println (apply str (interpose " " (interleave k v))))))

4 个答案:

答案 0 :(得分:89)

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

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

user> (seq {:foo 1 :bar 2})
([:foo 1] [:bar 2])

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"]

您可以使用keyvalfirstsecondnthget来获取密钥和值在这些载体之外。

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 [[k v] db] (prn k v))
:subprotocol "mysql"
:username "usr"
:classname "com.mysql.jdbc.Driver"
:subname "//100.100.100.100:3306/clo"
:password "pwd"

答案 1 :(得分:14)

你可以简单地做

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

结果是:

:a
1
:b
2

这是你在找什么?

答案 2 :(得分:4)

Brian的回答只是一个简短的补充:

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

(doseq [[k v] (map vector (keys db) (vals db))]
  (println (str k " " v)))

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

答案 3 :(得分:0)

目前尚不清楚是否要尝试解决一些问题,而不仅仅是打印出值(副作用),如果这就是您要追求的目标,那么我认为上述 customer_id account_id time count new_var 1: 1 AAA 2000-01-01 0 NA 2: 1 AAA 2000-02-01 1 0 3: 1 AAA 2000-03-01 2 0 4: 1 AAA 2000-04-01 3 0 5: 1 AAA 2000-05-01 4 0 6: 1 AAA 2000-06-01 5 1 7: 1 AAA 2000-07-01 6 1 8: 1 AAA 2000-08-01 7 1 9: 2 BBB 2008-01-01 0 NA 10: 2 BBB 2008-02-01 1 0 11: 2 BBB 2008-03-01 2 0 12: 2 BBB 2008-04-01 3 0 13: 2 BBB 2008-05-01 4 0 14: 2 BBB 2008-06-01 5 1 15: 2 BBB 2008-07-01 6 1 16: 2 BBB 2008-08-01 7 1 17: 2 BBB 2008-09-01 8 1 18: 2 BBB 2008-10-01 9 2 19: 2 BBB 2008-11-01 10 2 20: 2 BBB 2008-12-01 11 2 21: 2 BBB 2009-01-01 12 2 22: 2 BBB 2009-02-01 13 3 23: 2 BBB 2009-03-01 14 3 24: 2 BBB 2009-04-01 15 3 解决方案将是最惯用的方法。如果您要对地图的键和值进行一些操作并返回相同类型的数据结构,则应查看doseq,为此您可以找到here的文档

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