简体   繁体   中英

Merging maps in Clojure

I'm looking for a way to merge 4 separate lists of maps. I'm scraping a site that gives me a list of attrs in the form of data* below...

(def data1 '("1" "1" "1" "1"))
(def data2 '("2" "2" "2" "2"))
(def data3 '("3" "3" "3" "3"))
(def data4 '("4" "4" "4" "4"))

...and them I'm organizing them according to keys:

(map #(assoc {} :a %) data1)
(map #(assoc {} :b %) data2)
(map #(assoc {} :c %) data3)
(map #(assoc {} :d %) data4)

That code above produces the following data structure:

({:a "1"} {:a "1"} {:a "1"} {:a "1"})
({:b "2"} {:b "2"} {:b "2"} {:b "2"})
({:c "3"} {:c "3"} {:c "3"} {:c "3"})
({:d "4"} {:d "4"} {:d "4"} {:d "4"})

I want to combine these lists vertically, so I have the following:

(def want [{:a "1", :b "2", :c "3", :d "4"}
           {:a "1", :b "2", :c "3", :d "4"}
           {:a "1", :b "2", :c "3", :d "4"}
           {:a "1", :b "2", :c "3", :d "4"}])

This would allow me to iterate over the list of maps and select a specific value from each map, spitting them out on a webpage. But I'm not sure how to get the data structure I want . Any help is appreciated...

Map takes every combination of firsts, seconds, etc. from the provided collections and performs a function on each. So it's quite good for transposing collections. Vector is shown here as the simplest function to illustrate the transposition:

(map vector
  [{:a "1"} {:a "1"} {:a "1"} {:a "1"}]
  [{:b "2"} {:b "2"} {:b "2"} {:b "2"}]
  [{:c "3"} {:c "3"} {:c "3"} {:c "3"}]
  [{:d "4"} {:d "4"} {:d "4"} {:d "4"}]))

=>([{:a "1"} {:b "2"} {:c "3"} {:d "4"}]
   [{:a "1"} {:b "2"} {:c "3"} {:d "4"}]
   [{:a "1"} {:b "2"} {:c "3"} {:d "4"}]
   [{:a "1"} {:b "2"} {:c "3"} {:d "4"}])

Merge combines hash-maps:

(merge {:a "1"} {:b "2"} {:c "3"} {:d "4"})
=> {:d "4", :c "3", :b "2", :a "1"}

Combine the two for the effect you want:

(map merge
     [{:a "1"} {:a "1"} {:a "1"} {:a "1"}]
     [{:b "2"} {:b "2"} {:b "2"} {:b "2"}]
     [{:c "3"} {:c "3"} {:c "3"} {:c "3"}]
     [{:d "4"} {:d "4"} {:d "4"} {:d "4"}]))

=>({:d "4", :c "3", :b "2", :a "1"}
   {:d "4", :c "3", :b "2", :a "1"}
   {:d "4", :c "3", :b "2", :a "1"}
   {:d "4", :c "3", :b "2", :a "1"})

Its not clear to me why you would do the intermediate step of

(map #(assoc {} :a %) ...)

If your data is

(def data [["1" "1" "1" "1"] 
           ["2" "2" "2" "2"] 
           ["3" "3" "3" "3"] 
           ["4" "4" "4" "4"]])

And your keys are

(def my-keys [:a :b :c :d])

Then you can just use zipmap

(mapv zipmap (repeat my-keys) (apply map list data))


;=> [{:d "4", :c "3", :b "2", :a "1"}
;    {:d "4", :c "3", :b "2", :a "1"}
;    {:d "4", :c "3", :b "2", :a "1"}
;    {:d "4", :c "3", :b "2", :a "1"}]

Note the (apply map list data) is used to transpose the data to the correct orientation with respect to the keys.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM