Search code examples
clojure

clojure: given a list of maps, get the total sum value of a specific key value


Input: [{:a "ID1" :b 2} {:a "ID2" :b 4}]

I want to only add up all the keys :b and produce the following:

Result: 6

I thought about doing a filter? to pull all the numbers into vector and add it all up but this seems like doing work twice. I can't use merge-with + here since the :a has a string in it. Do I use a reduce here with a function that will pull the appropriate key?

(reduce (fn [x] (+ (x :b))) 0 list-of-maps)

It would be even nicer if I could retain the map structure with updated value ({:a "ID1" :b 6}) but since I don't really need the other keys, just the total sum is fine.


Solution

  • I want to only add up all the keys :b and produce the following:

    Result: 6

    I believe workable code is:

    (def m1 {:a 1, :b 2})
    (def m2 {:a 11, :b 12})
    (def m3 {:a 21, :b 22})
    (def ms [m1 m2 m3])
    
    (->> ms
         (map :b)
         (reduce +))
    

    I feel use of ->> here can help readability in your situation.

    This says to take action on ms, which is defined to be a vector of maps, threading incremental results through the remaining forms.

    The first thing is to transform each entry of maps using the keyword :b as a function on each, extracing the value corresponding to that key, resulting in the sequence:

    (2 12 22)
    

    You can then apply reduce exactly as you intuit across that seq to get the result:

    user=> (def m1 {:a 1, :b 2})
    #'user/m1
    user=>     (def m2 {:a 11, :b 12})
    #'user/m2
    user=>     (def m3 {:a 21, :b 22})
    #'user/m3
    user=>     (def ms [m1 m2 m3])
    #'user/ms
    user=>     (->> ms
      #_=>          (map :b)
      #_=>          (reduce +))
    36
    

    I'm a tad confused by what you intend by this part of the question:

    It would be even nicer if I could retain the map structure with updated value ({:a "ID1" :b 6})

    Do you want to have each value for :b across all maps contain the sum of them all in a result, or something else?