Any ideas what ????
should be? Is there a built in?
What would be the best way to accomplish this task?
(def v [\"one\" \"two\" \"three\" \"two
As of Clojure 1.4 clojure.contrib.seq (and thus the positions
function) is not available as it's missing a maintainer:
http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go
The source for clojure.contrib.seq/positions
and it's dependency clojure.contrib.seq/indexed
is:
(defn indexed
"Returns a lazy sequence of [index, item] pairs, where items come
from 's' and indexes count up from zero.
(indexed '(a b c d)) => ([0 a] [1 b] [2 c] [3 d])"
[s]
(map vector (iterate inc 0) s))
(defn positions
"Returns a lazy sequence containing the positions at which pred
is true for items in coll."
[pred coll]
(for [[idx elt] (indexed coll) :when (pred elt)] idx))
(positions #{2} [1 2 3 4 1 2 3 4]) => (1 5)
Available here: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions
I'd go with reduce-kv
(defn find-index [pred vec]
(reduce-kv
(fn [_ k v]
(if (pred v)
(reduced k)))
nil
vec))
Stuart Halloway has given a really nice answer in this post http://www.mail-archive.com/clojure@googlegroups.com/msg34159.html.
(use '[clojure.contrib.seq :only (positions)])
(def v ["one" "two" "three" "two"])
(positions #{"two"} v) ; -> (1 3)
If you wish to grab the first value just use first
on the result.
(first (positions #{"two"} v)) ; -> 1
EDIT: Because clojure.contrib.seq
has vanished I updated my answer with an example of a simple implementation:
(defn positions
[pred coll]
(keep-indexed (fn [idx x]
(when (pred x)
idx))
coll))
Here's my contribution, using a loop
ing structure and returning nil
on failure.
I try to avoid loops when I can, but it seems fitting for this problem.
(defn index-of [xs x]
(loop [a (first xs)
r (rest xs)
i 0]
(cond
(= a x) i
(empty? r) nil
:else (recur (first r) (rest r) (inc i)))))
(defn find-thing [needle haystack]
(keep-indexed #(when (= %2 needle) %1) haystack))
But I'd like to warn you against fiddling with indices: most often than not it's going to produce less idiomatic, awkward Clojure.
Built-in:
user> (def v ["one" "two" "three" "two"])
#'user/v
user> (.indexOf v "two")
1
user> (.indexOf v "foo")
-1
If you want a lazy seq of the indices for all matches:
user> (map-indexed vector v)
([0 "one"] [1 "two"] [2 "three"] [3 "two"])
user> (filter #(= "two" (second %)) *1)
([1 "two"] [3 "two"])
user> (map first *1)
(1 3)
user> (map first
(filter #(= (second %) "two")
(map-indexed vector v)))
(1 3)