keep-indexed

added
1.2

ns
clojure.core

type
function

(keep-indexed f) (keep-indexed f coll)

Returns a lazy sequence of the non-nil results of (f index item). Note,
this means false return values will be included.  f must be free of
side-effects.  Returns a stateful transducer when no collection is
provided.

                user=> (keep-indexed #(if (odd? %1) %2) [:a :b :c :d :e])
(:b :d)
            
                user=> (keep-indexed #(if (pos? %2) %1) [-9 0 29 -7 45 3 -8])
(2 4 5)
;; f takes 2 args: 'index' and 'value' where index is 0-based
;; when f returns nil the index is not included in final result
user=> (keep-indexed (fn [idx v]
                       (if (pos? v) idx)) [-9 0 29 -7 45 3 -8])
(2 4 5)
            
                (defn position [x coll & {:keys [from-end all] :or {from-end false all false}}]
  (let [all-idxs (keep-indexed (fn [idx val] (when (= val x) idx)) coll)]
  (cond
   (true? from-end) (last all-idxs)
   (true? all)      all-idxs
   :else            (first all-idxs))))

user> (position [1 1] [[1 0][1 1][2 3][1 1]])
1
user> (position [1 1] [[1 0][1 1][2 3][1 1]] :from-end true)
3
user> (position [1 1] [[1 0][1 1][2 3][1 1]] :all true)
(1 3)

user> (def foo (shuffle (range 10)))
#'user/foo
user> foo
(5 8 9 1 2 7 0 6 3 4)
user> (position 5 foo)
0
user> (position 0 foo)
6
            
                ;; Simpler version of "position" above
;; Get position of first element that satisfies the predicate
(let [predicate #(= 1 %)
      sequence [3 2 4 1 5 6 7]]
  (first (keep-indexed (fn [i x] (when (predicate x) i)) 
                sequence)))

;; The same logic but implemented with map-indexed
(let [predicate #(= 1 %)
      sequence [3 2 4 1 5 6 7]]
  (some identity 
        (map-indexed (fn [i x] (when (predicate x) i)) 
                     sequence)))