web-dev-qa-db-fra.com

Comment trouver l'index d'un élément dans un vecteur?

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
74

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)
123
Brian Carper

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))
40
ponzao
(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.

24
cgrand

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

13
lsh

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
5

Voici ma contribution, en utilisant une structure looping 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)))))
2
Josh.F

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)))))
2
Joshua