Toutes les idées que ????
devrait être? Y a-t-il un intégré? Quelle serait la meilleure façon d'accomplir cette tâche?
(def v ["one" "two" "three" "two"])
(defn find-thing [ thing vectr ]
(????))
(find-thing "two" v) ; ? maybe 1, maybe '(1,3), actually probably a lazy-seq
Intégré:
user> (def v ["one" "two" "three" "two"])
#'user/v
user> (.indexOf v "two")
1
user> (.indexOf v "foo")
-1
Si vous voulez une séquence paresseuse des indices pour toutes les correspondances:
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)
Stuart Halloway a donné une réponse vraiment sympa dans cet article http://www.mail-archive.com/[email protected]/msg34159.html .
(use '[clojure.contrib.seq :only (positions)])
(def v ["one" "two" "three" "two"])
(positions #{"two"} v) ; -> (1 3)
Si vous souhaitez récupérer la première valeur, utilisez simplement first
sur le résultat.
(first (positions #{"two"} v)) ; -> 1
EDIT: Parce que clojure.contrib.seq
a disparu J'ai mis à jour ma réponse avec un exemple d'implémentation simple:
(defn positions
[pred coll]
(keep-indexed (fn [idx x]
(when (pred x)
idx))
coll))
(defn find-thing [needle haystack]
(keep-indexed #(when (= %2 needle) %1) haystack))
Mais je voudrais vous mettre en garde contre toute manipulation d'indices: le plus souvent, cela va produire un Clojure moins idiomatique et maladroit.
Depuis Clojure 1.4 clojure.contrib.seq (et donc la fonction positions
) n'est pas disponible car il manque un mainteneur: http://dev.clojure.org/display/design/Where+ Did + Clojure.Contrib + Go
La source de clojure.contrib.seq/positions
et c'est la dépendance clojure.contrib.seq/indexed
est:
(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)
Disponible ici: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions
J'essayais de répondre à ma propre question, mais Brian m'a battu avec une meilleure réponse!
(defn indices-of [f coll]
(keep-indexed #(if (f %2) %1 nil) coll))
(defn first-index-of [f coll]
(first (indices-of f coll)))
(defn find-thing [value coll]
(first-index-of #(= % value) coll))
(find-thing "two" ["one" "two" "three" "two"]) ; 1
(find-thing "two" '("one" "two" "three")) ; 1
;; these answers are a bit silly
(find-thing "two" #{"one" "two" "three"}) ; 1
(find-thing "two" {"one" "two" "two" "three"}) ; nil
Voici ma contribution, en utilisant une structure loop
ing et en renvoyant nil
en cas d'échec.
J'essaie d'éviter les boucles quand je le peux, mais cela semble convenir à ce problème.
(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)))))
J'ai récemment dû trouver des index plusieurs fois ou plutôt j'ai choisi car c'était plus facile que de trouver une autre façon d'aborder le problème. En cours de route, j'ai découvert que mes listes Clojure n'avaient pas la méthode .indexOf (Object object, int start). J'ai traité le problème comme ceci:
(defn index-of
"Returns the index of item. If start is given indexes prior to
start are skipped."
([coll item] (.indexOf coll item))
([coll item start]
(let [unadjusted-index (.indexOf (drop start coll) item)]
(if (= -1 unadjusted-index)
unadjusted-index
(+ unadjusted-index start)))))