Search code examples
clojureclojurescript

Clojure nested for loop with index


I've been trying to idiomatically loop through a nested vector like below:

[[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]]

I also need to return the coordinates once I've found a value. eg The call (find-key-value 3) should return [1 2]

This is what I have so far but its not giving me the output that I need it would return ([] [] [] [] [] [1 2] [] [] []) where as i only need [1 2]

(defn find-key-value
  [array value]
  (for [x (range 0 (count array))]
    (loop [y   0
           ret []]
      (cond
        (= y (count (nth array x))) [x y]
        :else (if (= value (get-in array [x y]))
                (recur (+ 1 y) (conj ret [x y]))
                (recur (+ 1 y) ret))))))

Anyone have any ideas on how I can fix my code to get to my desired solution or have a better approach in mind!


Solution

  • A list comprehension can be used to find coordinates of all values satisfying a predicate:

    (defn find-locs [pred coll]
      (for [[i vals] (map-indexed vector coll)
            [j val] (map-indexed vector vals)
            :when (pred val)]
        [i j]))
    
    (find-locs #(= 3 %) [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
    => ([1 5])
    
    (find-locs zero? [[0 1 1] [1 1 1] [1 0 1]])
    => ([0 0] [2 1])
    

    The posed question seems to imply that the keywords in the inputs should be ignored, in which case the answer becomes:

    (defn find-locs-ignore-keyword [pred coll]
      (for [[i vals] (map-indexed vector coll)
            [j val] (map-indexed vector (remove keyword? vals))
            :when (pred val)]
        [i j]))
    
    (find-locs-ignore-keyword #(= 3 %) [[:a 1 :b 1 :c 1] [:a 1 :b 1 :c 3] [:a 1 :b 1 :c 1]])
    => ([1 2])