0

I have a return hashmap from firestore as below:

#object[java.util.HashMap 0x163df674 {reference=NEW_USER, type=Promotion, includedScans=100}]
#object[java.util.HashMap 0x140a8085 {reference=NEW_USER, type=Promotion, includedScans=50}]

......

I would like to sum all the "includedScans" of them in Clojure

Expected result: 150

Can someone please help! Thanks

giahuy
  • 57
  • 4
  • Have you tried already some code you could share? At first glance this looks like a two part question: how to extract the value you are interested and next how to sum it up. Both answered already one ore another time here. So maybe you have some special problem in regard firestore? – cfrick Jan 30 '18 at 08:28

3 Answers3

1

1 - using java.util.HashMap

given n maps,

user=> (def map1 (java.util.HashMap. {:reference "user1" :type "Promotion" :included-scans 100}))
#'user/map1

user=> (def map2 (java.util.HashMap. {:reference "user1" :type "Promotion" :included-scans 50}))
#'user/map2

map over vector of hash-maps,

user=> (map #(:included-scans %) [map1 map2]) ;; #() represents a function on each element
(100 50)

;; alternative way is
user=> (map :included-scans [map1 map2])
(100 50)

sum the values using reduce function,

user=> (reduce + (map #(:included-scans %) [map1 map2]))
150

Note that above map is java.lang.HashMap, clojure has its own data-structure as well called clojure.lang.PersistentHashMap

2 - Using clojure.lang.PersistentHashMap,

given n number of maps,

user=> (def map1 (hash-map :reference "user1" :type "Promotion" :included-scans 100))
#'user/map1

user=> (def map2 (hash-map :reference "user1" :type "Promotion" :included-scans 50))
#'user/map2

You simply can map over them and get the required key which is :included-scans in your case,

user=> (map #(:included-scans %) [map1 map2])
(100 50)

Then to sum up using reduce function,

user=> (reduce + (map #(:included-scans %) [map1 map2]))
150

references

https://clojuredocs.org/clojure.core/hash-map

Clojure: working with a java.util.HashMap in an idiomatic Clojure fashion

prayagupa
  • 30,204
  • 14
  • 155
  • 192
  • 2
    Since `keywords` are function of maps to their values, writing `(map #(:scans %) [map1 map2])` is equivalent to `(map :scans [map1 map2])` – Shlomi Jan 30 '18 at 07:10
  • @prayagupd can you advise me to write the unit test for this? `(defn get-includedScans-value [snapshot] (-> snapshot .getData (.get "includedScans")))` I have define the map as you told: `(def map1 (java.util.HashMap. {:reference "user1" :type "Promotion" :included-scans 100}))` But it keeps saying that `actual: java.lang.IllegalArgumentException: No matching field found: getData for class java.util.HashMap` – giahuy Feb 01 '18 at 10:12
0

You can follow the code samples from here to convert the Java-Map into an Clojure-Map.

user> (java.util.HashMap. {:foo :bar})
#<HashMap {:foo=:bar}>

user> (into {} (java.util.HashMap. {:foo :bar}))
{:foo :bar}

After converting, the summarizing could be done like this:

You can use the Java-Hashmap like any other Map in Clojure (see comments). The summarizing could be done like this:

user> (reduce (fn[s m] (+ s (get m "includedScans"))) 0 [map1 map2 ...])
seegy
  • 1
  • 2
  • You actually dont need to convert your maps at all, `(reduce (fn[s m] (+ s (get m :foo))) 0 [(java.util.HashMap. {:foo 4}) (java.util.HashMap. {:foo 3})])` works just fine like this as well – Shlomi Jan 30 '18 at 07:07
0

You can use transduce to do this in an efficient, non-lazy manner.

(transduce (map #(get % "includedScans" 0)) + 0 [map1 map2 ...])
dpassen
  • 1,276
  • 1
  • 10
  • 14