2011-01-28 12 views
66

¿Alguna idea de qué debería ser ????? ¿Hay un built-in? ¿Cuál sería la mejor manera de lograr esta tarea?¿Cómo encuentro el índice de un elemento en un vector?

(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 
+0

Brian's es claramente la respuesta a esta pregunta, pero debajo, cgrand y Alex Stoddard conspiran para responder la pregunta que debería haber hecho. –

+0

Nada le impide hacer la pregunta correcta en una pregunta separada :) –

Respuesta

107

incorporado:

user> (def v ["one" "two" "three" "two"]) 
#'user/v 
user> (.indexOf v "two") 
1 
user> (.indexOf v "foo") 
-1 

Si quieres un ss perezoso de los índices de todos los partidos:

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) 
+1

Sweet, gracias Brian, mi doc-searcher no encontró indexOf, presumiblemente porque es Java. Tendré que trabajar en eso. –

+1

@John: Sí. El punto antes de indexOf indica la interoperabilidad de Java. Llama al método 'indexOf' en java.lang.String. java.lang se importa por defecto. Para ver más ejemplos, vea http: // clojure.org/java_interop – dermatthias

+19

Es el método 'indexOf' del vector que se llama, no String's:' # ' – vemv

3

yo estaba tratando de responder a mi propia pregunta, sino que se golpeaba Brian a mí con una mejor respuesta!

(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 
35

Stuart Halloway ha dado una respuesta muy agradable en este post 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 desea agarrar el primer valor sólo tiene que utilizar first en el resultado.

(first (positions #{"two"} v)) ; -> 1 

EDIT: Debido clojure.contrib.seq ha desaparecido He actualizado mi respuesta con un ejemplo de una implementación simple:

(defn positions 
    [pred coll] 
    (keep-indexed (fn [idx x] 
        (when (pred x) 
        idx)) 
       coll)) 
+0

¡Muy bien! Este es el tipo de respuesta que estaba esperando. –

+2

No es que afecte el mérito de esta respuesta, pero seq-utils ha cambiado ahora solo clojure.contrib.seq. –

+1

@John, cierto, lo arreglé. ¡Gracias! – ponzao

23
(defn find-thing [needle haystack] 
    (keep-indexed #(when (= %2 needle) %1) haystack)) 

Pero me gustaría avisar de tocar el violín con índices: más a menudo de lo contrario, producirá menos idiomática, incómoda Clojure.

+0

¡Qué bueno 'cuándo'! Estoy de acuerdo con los índices en general, pero tengo un archivo csv, y los nombres de los campos están en el encabezado, y quiero obtener el campo "campo" de cada fila, entonces lo que estoy haciendo es buscar "campo" arriba en el encabezado, y luego nada en las filas. Puedo pensar en cosas extrañas que hacer con interleave, pero ¿hay alguna buena manera que no use índices explícitos que sean legibles? –

+8

Cuando tengo ese caso de uso - encabezados de csv - acabo de construir un mapa para hacer la búsqueda (asumiendo encabezados de columna únicos). El mapa _es_ luego mi función para hacer búsqueda de índice. (let [header-index (zipmap header-vector (iterate inc 0))] ...) –

+0

Wow. ¡Respondió la pregunta que debería haber hecho! –

2

Hace poco tuve que encontrar índices varias veces o más bien elegí porque era más fácil que encontrar otra forma de abordar el problema. En el camino, descubrí que mis listas Clojure no tenían el método .indexOf (objeto Object, int start). Tuve que lidiar con el problema de esta manera:

(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))))) 
13

A partir de Clojure 1.4 clojure.contrib.seq (y por lo tanto la función positions) no está disponible, ya que le falta un mantenedor: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

La fuente de clojure.contrib.seq/positions y es la dependencia clojure.contrib.seq/indexed es:

(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 aquí: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions

+2

Gracias por publicar esta versión. Desde 1.2 también puede reemplazar (iterar inc 0) simplemente (rango). – dribnet

2

Aquí está mi contribución, usando una estructura de loop y devolviendo nil en caso de falla.

Intento evitar bucles cuando puedo, pero parece apropiado para este problema.

(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))))) 
Cuestiones relacionadas