How to Iterate over Map Keys and Values in Clojure?

后端 未结 4 1848
感动是毒
感动是毒 2020-12-23 15:48

I have the following map which I want to iterate:

(def db {:classname \"com.mysql.jdbc.Driver\" 
         :subprotocol \"mysql\" 
         :subname \"//100.         


        
4条回答
  •  鱼传尺愫
    2020-12-23 16:29

    That's expected behavior. (doseq [x ... y ...]) will iterate over every item in y for every item in x.

    Instead, you should iterate over the map itself once. (seq some-map) will return a list of two-item vectors, one for each key/value pair in the map. (Really they're clojure.lang.MapEntry, but behave like 2-item vectors.)

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

    doseq can iterate over that seq just like any other. Like most functions in Clojure that work with collections, doseq internally calls seq on your collection before iterating over it. So you can simply do this:

    user> (doseq [keyval db] (prn keyval))
    [:subprotocol "mysql"]
    [:username "usr"]
    [:classname "com.mysql.jdbc.Driver"]
    [:subname "//100.100.100.100:3306/clo"]
    [:password "pwd"]
    

    You can use key and val, or first and second, or nth, or get to get the keys and values out of these vectors.

    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"
    

    More concisely, you can use destructuring to bind each half of the map entries to some names that you can use inside the doseq form. This is idiomatic:

    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"
    

提交回复
热议问题