cliff
cliff

Reputation: 43

merging a sequence of maps

I have two maps, of the form:

(def h1 {:p1 {:x {:port :p1 :instr :x :qty 10}}})
(def h2 {:p1 {:y {:port :p1 :instr :y :qty 11}}})

When I merge them using

(apply (partial merge-with merge) [h1 h2])

I get the correct result:

-> {:p1 {:y {:port :p1, :qty 11, :instr :y}, :x {:port :p1, :qty 10, :instr :x}}

However, If I try reducing over a sequence of maps:

(reduce (fn [r m] apply (partial merge-with merge) r m) {} [h1 h2])

I get only the first map as a result:

-> {:p1 {:y {:port :p1, :qty 11, :instr :y}}}

I would expect the same result. What am I doing wrong?

Upvotes: 0

Views: 345

Answers (1)

Thumbnail
Thumbnail

Reputation: 13473

You forgot to apply the apply. In

(fn [r m] apply (partial merge-with merge) r m)

... the implicit do in the fn form performs a series of evaluations, returning the result of the last one. Ignoring side-effects (and there are none), the function is equivalent to

(fn [r m] m)

as you observed.

The reduce takes the sequence of maps apart, so you don't need the apply:

(reduce (fn [r m] (merge-with merge r m)) {} [h1 h2])
; {:p1
;  {:y {:qty 11, :instr :y, :port :p1},
;   :x {:qty 10, :instr :x, :port :p1}}}

If you are determined to use the same structure for the function, you have to do it this way:

(reduce (fn [r m] (apply (partial merge-with merge) [r m])) {} [h1 h2])
; {:p1
;  {:y {:qty 11, :instr :y, :port :p1},
;   :x {:qty 10, :instr :x, :port :p1}}}

apply expects a sequence as its last argument, which it flattens into the trailing arguments to its first (function) argument.

Upvotes: 4

Related Questions