0

I'm calling a Javascript library and getting a Map Iterator back (which in Javascript you use with for ... in)

How do I turn this into a ClojureScript sequence so I can call for on it?

interstar
  • 26,048
  • 36
  • 112
  • 180

1 Answers1

1

By looking at the MDN documentation on Map iterator you can check that you can navigate the iterator with the .next() method which will return a JS object with 2 properties: value and done, where value will contain an Array of size 2 with the key and value for each entry on the Map, and done, which will be false until the iterator is exhausted (no more entries).

Using this, we can create a ClojureScript function that takes the iterator and builds a Map (or a ClojureScript map if you remove the clj->js).

(defn ^:export iterToMap [iter]
  (loop [acc {}]
    (let [elem (.next iter)]
      (if (.-done elem) ;; no more elements
        (clj->js acc) ;; or just use `acc` for a regular CLJS map
        (let [[k v] (array-seq (.-value elem))]
          (recur (assoc acc k v)))))))

I used the ^:export metadata flag so that you can call the function from the console. If you save this function in say app/main.cljs, the function will be available as app.main.iterToMap() in the global JS object.

You can use it as follows in the Developer Console:

> const map1 = new Map();
> map1.set("0", "zero");
> map1.set("1", "one");

// Now call the function, note that map1.entries() returns an Iterator:

> app.main.iterToMap(map1.entries());

// Returns:
Object { 0: "zero", 1: "one" }

If you want a sequence of key-value pairs, you can use the same principle to create a lazy-sequence, you just need to remember to hold a reference to the iterator so you can extract the next item.

Denis Fuenzalida
  • 3,271
  • 1
  • 17
  • 22