0

I am fairly new to Clojure and would help help with some code. I have a function which takes a vector and i would like to loop through the vector and get the value at an index 'i' and the value of 'i' itself. 'i' is the value which is incremented in the loop.

I have checked 'for' at the clojure docs at for and wrote the following code.

(for [i some-vector]
      (print (get-intersec i (.length some-vector) loop-count)))

The loop-count variable is supposed to be the loop count.

I have also checked loop but it does not seem like a feasible solution. Can someone help me with a clojure function i can use or help me write a macro or function that can do that.

Thank you.

Ps: To solve my problem, i use my own counter but would like a better solution.

3 Answers 3

6

First, keep in mind that for is for list comprehension, that is, creating new sequences. For looping through a sequence for some side effect, like printing, you probably want to use doseq.

To include a numeric count with each element as you loop through, you can use map-indexed:

(def xs [:a :b :c :d])

(doseq [[n elem] (map-indexed #(vector %1 %2) xs)]
  (println n "->" elem))

Output:

0 -> :a
1 -> :b
2 -> :c
3 -> :d

If you find yourself doing this a lot, like I did, you can create a macro:

(defmacro doseq-indexed [[[item idx] coll] & forms]
  `(doseq [[~idx ~item] (map-indexed #(vector %1 %2) ~coll)]
     ~@forms))

And use it like this:

> (doseq-indexed [[n elem] xs] (println n "->" elem))
0 -> :a
1 -> :b
2 -> :c
3 -> :d
Sign up to request clarification or add additional context in comments.

Comments

3

Don't forget dotimes for simple stuff like this:

  (let [data [:a :b :c :d]]
    (dotimes [i (count data)]
      (println i " -> " (data i))
               ; or (nth data i)
               ; or (get data i)
      ))

with result

0  ->  :a
1  ->  :b
2  ->  :c
3  ->  :d

Using loop/recur would look like this:

  (let [data [:a :b :c :d]]
    (loop [i     0
           items data]
      (let [curr (first items)]
        (when curr
          (println i "->" curr)
          (recur (inc i) (rest items))))))

Update:

If you need this a lot, I already wrote a function that will add the index value to the beginning of each entry in a sequence:

(ns tst.demo.core
  (:use tupelo.test)
  (:require [tupelo.core :as t]) )

(dotest
  (let [data [:a :b :c :d]]
    (t/spy-pretty :indexed-data
      (t/indexed data))))

with result

:indexed-data =>
  ([0 :a]
   [1 :b]
   [2 :c]
   [3 :d])

The general signature is:

(indexed & colls)

Given one or more collections, returns a sequence of indexed tuples 
from the collections like:

(indexed xs ys zs) -> [ [0 x0 y0 z0]
                        [1 x1 y1 z1]
                        [2 x2 y2 z2]
                        ... ] 

Comments

1

If your not set on using for, you could use map-indexed e.g.

(map-indexed (fn [i v]
               (get-intersect v (.length some-vector) i))
             some-vector))

I don't know what get-intersect is and assume .length is java interop? Anyway, map-indexed expects a function of 2 arguments, the 1st is the index and the second is the value.

Comments

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.