0

I am new to clojure and can't really wrap my head around adding to a hashmap without using a typical for loop like other languages would. For example, if I have the following code segment:

(def empty-hashmap {})
(def big-hashmap (assoc empty-hashmap 1 2)) 

how would I iterate through and add 300 separate elements to the big hashmap? In this case I want my code to look something like

(def empty-hashmap {})
(def big-hashmap (assoc empty-hashmap n (abundance n)))

where n is the numbers 1 to 300 and it populates 300 elements into the big hashmap.

3 Answers 3

3

As Alan Thompson says, reduce is the general purpose tool for iterating over a sequence and accumulating a result. But if you need to make many "independent" changes, as here you associate keys in a map with values that don't depend on anything but the key, there are better tools. map is the general purpose tool for producing a new sequence based on an old one, and into is for turning sequences into maps. So, you can write

(into {}
      (map (fn [n] [n (abundance n)])
           (range 1 301)))

Note that (fn [n] [n (abundance n)]) could also be written (juxt identity abundance), though it's up to you which you find clearer.

Personally I don't like writing (map (fn [n] ...)) - usually if you need a (one-argument) lambda, for is a better tool than map. The into/for pairing is very common for tasks like this:

(into {}
      (for [n (range 1 301)]
        [n (abundance n)]))

I would not at all recommend using an atom just for a "more imperative feel". There are good times to use an atom, but beginners don't run into them super quickly, and this isn't one of them.

Sign up to request clarification or add additional context in comments.

Comments

0

Just wanted to add a reduce code example to @amalloy's answer:

  (let [keys [:a :b :c :d :e :f :g]
        vals [1  2  3  4  5  6  7]]
      (map vector keys vals))

  => ([:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7])

  
  (let [keys [:a :b :c :d :e :f :g]
        vals [1  2  3  4  5  6  7]]
    (reduce
      (fn [a [k v]] (assoc a k v))
      {}
      (map vector keys vals)))
  => {:a 1, :b 2, :c 3, :d 4, :e 5, :f 6, :g 7}

This uses reduce with an "accumulator function". For each iteration, the function is called with the old value of the map and a new key-value pair. It assoc's in the new value and returns a new map with an extra key-value pair. The initial value is provided as the second argument to reduce (the {} empty map).

Comments

-2

Reduce is a good option here, starting from my favorite template project:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test))

(verify
  (let [result (reduce  (fn [accum item]
                          (assoc accum item (str "item " item)))
                 {} ; initial empty map
                 (range 5)) ; list of items to add
                 ]
    (is= result
      {0 "item 0"
       1 "item 1"
       2 "item 2"
       3 "item 3"
       4 "item 4"})))

If you want a more imperative-style solution, you can always accumulate the result into an atom:

(verify
  (let [accum (atom {})]
    (doseq [idx (range 5)]
      (swap! accum
        #(assoc % idx (str "item " idx))))
    (is= @accum
      {0 "item 0"
       1 "item 1"
       2 "item 2"
       3 "item 3"
       4 "item 4"})))

5 Comments

reduce does not use an atom internally. What makes you think it does?
Yeah, IReduce is overkill to include here, so removed the comment.
I'm not aware of an implementation of IReduce that uses an atom, though I could certainly believe one exists. Do you have a pointer?
No, it is all pure Java with a mutable variable. I was already looking up the details when you posted the first comment (beat me to the punch again!). Here is the source for IPersistentVector.java: github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/…
Ah, sure, in Java you don't really have a choice. I don't think I'd compare that to an atom, or even call it mutable (though I agree, of course, the local is being reassigned). It's just Java's way of writing a loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.