Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Call a function for each element in a vector with it index

Say I have a vector:

(def data ["Hello" "World" "Test" "This"])

And I want to populate a table somewhere that has an api:

(defn setCell
  [row col value]
  (some code here))

Then what is the best way to get the following calls to happen:

(setCell 0 0 "Hello")
(setCell 0 1 "World")
(setCell 0 2 "Test")
(setCell 0 3 "This")

I found that the following will work:

(let [idv (map vector (iterate inc 0) data)]
  (doseq [[index value] idv] (setCell 0 index value)))

But is there a faster way that does not require a new temporary datastructure idv?

like image 642
Jeroen Dirks Avatar asked Oct 30 '09 17:10

Jeroen Dirks


4 Answers

You can get the same effect in a very clojure-idiomatic way by just mapping the indexes along with the data.

(map #(setCell 0 %1 %2) (iterate inc 0) data)

You may want to wrap this in a (doall or (doseq to make the calls happen now. It's just fine to map an infinite seq along with the finite one because map will stop when the shortest seq runs out.

like image 86
Arthur Ulfeldt Avatar answered Oct 23 '22 16:10

Arthur Ulfeldt


A bit late in the game but for people accessing this page: there is now (since clojure 1.2) a map-indexed function available in clojure.core.

One issue (unless I'm mistaken): there's no "pmap" equivalent, meaning that map-indexed computations cannot easily be parallelized. In that case, I'd refer to solutions offered above.

like image 35
Rollo Tomazzi Avatar answered Oct 23 '22 17:10

Rollo Tomazzi


The way you're doing it is idiomatic (and identical to clojure.contrib.seq-utils/indexed in fact). If you really want to avoid the extra data structure, you can do this:

(loop [data data, index 0]
  (when (seq data)
    (setCell 0 index (first data))
    (recur (rest data) (inc index))))

I'd use your version unless there was a good reason not to though.

like image 10
Brian Carper Avatar answered Oct 23 '22 16:10

Brian Carper


The nicest way would be to use clojure.contrib.seq-utils/indexed, which will look like this (using destructuring):

(doseq [[idx val] (indexed ["Hello" "World" "Test" "This"])]
  (setCell 0 idx val))
like image 8
pmf Avatar answered Oct 23 '22 16:10

pmf