Reputation:
With Clojure, how do I find the first index with a positive value in this vector [-1 0 3 7 9]
?
I know you can get the first result of something rather elegantly with first
and filter
:
(first (filter pos? [-1 0 99 100 101]))
This code returns the value 99
. The answer I want is the index which is 2
.
Upvotes: 31
Views: 9804
Reputation: 374
(defn first-idx
([pred]
(fn [coll] (first-idx pred coll)))
([pred coll]
(reduce-kv
(fn [_ idx val] (when (pred val) (reduced idx)))
nil
coll)))
(first-idx nil? [:a :b nil]) ;; ~> 2
((first-idx nil?) [:a :b :c nil]) ;; ~> 3
(first-idx nil? nil) ;; ~> nil
(first-idx nil? [:a :b :c]) ;; ~> nil
Upvotes: 0
Reputation: 494
I'm a little late to the party, but I prefer:
(defn index-of-pred
[pred coll]
(ffirst (filter (comp pred second) (map-indexed list coll))))
;; example usage
(index-of-pred pos? [-1 -2 -5 0 3 4 1 -100])
;=> 4
Upvotes: 1
Reputation: 12883
(defn pred-idx [pred [idx hist] cur]
(if (pred cur)
[(inc idx) (conj hist idx)]
[(inc idx) hist]))
(defn idx-filter [pred col]
(second (reduce (partial pred-idx pred) [0 []] col)))
(first (idx-filter pos? [-1 0 99 100 101]))
2
Not sure if this is better, but it works. I think it forces evaluation of the entire sequence though, and if you need all indices that would be better. The correct thing to do is probably turn it into a lazy sequence somehow, but I'm done for the evening.
Upvotes: 1
Reputation:
(first (filter #(not (nil? %)) (map #(when (pos? %1) %2) [-1 1 0 99 100 101] (range))))
Map can take one or more collections and return one list,put condition on map,and filter nil.
Upvotes: 1
Reputation: 236004
Try this:
(defn first-index
([pred coll] (first-index coll pred 0))
([pred coll idx]
(cond (= coll '()) -1
(pred (first coll)) idx
:else (recur pred (rest coll) (inc idx)))))
And use it like this:
(defn is-pos? [x]
(> x 0))
(first-index is-pos? [-1 0 3 7 9])
It returns the zero-based index of the first element that satisfies the predicate (is-pos?
in the example), or -1 if no element matches the predicate.
Upvotes: 0
Reputation: 19642
Using keep-indexed
you can get a sequence of indices for which a predicate is satisfied:
(defn indices [pred coll]
(keep-indexed #(when (pred %2) %1) coll))
With this simple function you'll solve your problem with the expression
user=> (first (indices pos? [-1 0 99 100 101]))
2
Note that, due to the lazyness of keep-indexed
(and indices
), the entire sequence need not be realized so no extraneous calculations are performed.
Upvotes: 48
Reputation: 76
(defn first-pos [x]
(loop [arr x n 0]
(if (pos? (first arr))
n
(recur (next arr) (inc n)))))
This is a good example of using functional programming's powerful tail recursion.
Upvotes: 3