Jak znaleźć indeks elementu w wektorze?


84

Jakieś pomysły, co ????powinno być? Czy jest wbudowany? Jaki byłby najlepszy sposób wykonania tego zadania?

(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

Brian's jest oczywiście odpowiedzią na to pytanie, ale poniżej cgrand i Alex Stoddard spiskują, aby odpowiedzieć na pytanie, które powinienem był zadać.
John Lawrence Aspden

Nic nie stoi na przeszkodzie, aby zadać poprawne pytanie w osobnym pytaniu :)
Jonathan Benn

Odpowiedzi:


138

Wbudowane:

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

Jeśli chcesz uzyskać leniwą sekwencję indeksów dla wszystkich dopasowań:

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)

3
Super, dzięki Brian, moja wyszukiwarka dokumentów nie znalazła indexOf, prawdopodobnie dlatego, że jest to Java. Muszę nad tym popracować.
John Lawrence Aspden

2
@John: Tak. Kropka przed indexOf wskazuje na współpracę między Javą. Wywołuje metodę „indexOf” w java.lang.String. Domyślnie plik java.lang jest importowany. Więcej przykładów można znaleźć na stronie clojure.org/java_interop
dermatthias

25
indexOf#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
Wywoływana

44

Stuart Halloway dał naprawdę miłą odpowiedź w tym poście 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)

Jeśli chcesz pobrać pierwszą wartość, po prostu użyj firstwyniku.

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

EDYCJA: Ponieważ clojure.contrib.seqzniknął, zaktualizowałem swoją odpowiedź przykładem prostej implementacji:

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

Bardzo dobrze! Takiej odpowiedzi się spodziewałem.
John Lawrence Aspden

2
Nie żeby miało to wpływ na wartość tej odpowiedzi, ale seq-utils zostało teraz zmienione tylko clojure.contrib.seq.
John Lawrence Aspden

1
@John, prawda, naprawiłem to. Dzięki!
ponzao

skąd wziąć clojure.contib.seqclojure 1.6? Brak biblioteki na liście: dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k

@ d9k, "Jeśli przestrzeń nazw clojure.contrib jest wymieniona tutaj, ale nie ma szczegółów migracji, oznacza to, że nikt nie zgłosił się na ochotnika do utrzymywania tej przestrzeni nazw." Dodałem przykładową implementację dla positions.
ponzao

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

Ale chciałbym was ostrzec przed majstrowaniem przy indeksach: najczęściej da to mniej idiomatyczny, niezręczny Clojure.


Och, miło „kiedy”! Generalnie zgadzam się co do indeksów, ale mam plik csv, a nazwy pól są w nagłówku i chcę pobrać pole „pole” z każdego wiersza, więc to, co robię, to szukanie „pola” w górę w nagłówku, a następnie nthing wiersze. Mogę wymyślić dziwne rzeczy, które można zrobić z przeplotem, ale czy istnieje fajny sposób, który nie używa wyraźnych indeksów, które są czytelne?
John Lawrence Aspden

8
Kiedy mam ten przypadek użycia - nagłówki csv - właśnie zbudowałem mapę do wyszukiwania (zakładając unikalne nagłówki kolumn). Mapa jest wtedy moją funkcją do przeszukiwania indeksu. (let [header-index (zipmap header-vector (iterate inc 0))] ...)
Alex Stoddard

1
Łał. Odpowiedziałeś na pytanie, które powinienem był zadać!
John Lawrence Aspden

3
Cóż, zaproponowałbym coś bardzo podobnego do rozwiązania Alexa. (-> wiersz nagłówka-indeksu „nazwa_kolumny”) i masz swoją wartość.
cgrand

14

Od Clojure 1.4 clojure.contrib.seq (a tym samym positionsfunkcja) nie jest dostępna, ponieważ nie ma opiekuna: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

Źródłem clojure.contrib.seq/positionsi zależnością clojure.contrib.seq/indexedjest:

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

Dostępne tutaj: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions


2
Dziękujemy za opublikowanie tej wersji. Od wersji 1.2 można również zamienić (iteruj przyrost 0) na po prostu (zakres).
drybling

6

Próbowałem odpowiedzieć na własne pytanie, ale Brian pobił mnie lepszą odpowiedzią!

(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

3

Oto mój wkład, wykorzystujący loopstrukturę ing i powracający nilpo niepowodzeniach.

Staram się unikać pętli, kiedy mogę, ale wydaje się, że pasuje to do tego problemu.

(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

Ostatnio musiałem kilka razy znaleźć indeksy, a raczej zdecydowałem się na to, ponieważ było to łatwiejsze niż wymyślanie innego sposobu podejścia do problemu. Po drodze odkryłem, że moje listy Clojure nie mają metody .indexOf (Object object, int start). Z problemem poradziłem sobie tak:

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

0

Poszedłbym z redukcją kv

(defn find-index [pred vec]
  (reduce-kv
    (fn [_ k v]
      (if (pred v)
        (reduced k)))
    nil
    vec))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.