Wie finde ich den Index eines Elements in einem Vektor?


83

Irgendwelche Ideen was ????sein soll? Gibt es eine eingebaute? Was wäre der beste Weg, um diese Aufgabe zu erfüllen?

(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 ist eindeutig die Antwort auf diese Frage, aber unten verschwören sich cgrand und Alex Stoddard, um die Frage zu beantworten, die ich hätte stellen sollen.
John Lawrence Aspden

Nichts hindert Sie daran, die richtige Frage in einer separaten Frage zu stellen :)
Jonathan Benn

Antworten:


134

Eingebaut:

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

Wenn Sie eine faule Abfolge der Indizes für alle Übereinstimmungen wünschen:

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
Süß, danke Brian, mein Doc-Sucher hat indexOf nicht gefunden, vermutlich weil es Java ist. Ich werde daran arbeiten müssen.
John Lawrence Aspden

2
@ John: Ja. Der Punkt vor indexOf gibt Java Interop an. Es ruft die Methode 'indexOf' in java.lang.String auf. java.lang wird standardmäßig importiert. Weitere Beispiele finden Sie unter clojure.org/java_interop
dermatthias

25
Es ist die indexOfMethode des Vektors , die aufgerufen wird, nicht die von String:#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
vemv

44

Stuart Halloway hat in diesem Beitrag eine wirklich nette Antwort gegeben: 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)

Wenn Sie den ersten Wert abrufen möchten, verwenden Sie einfach firstdas Ergebnis.

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

EDIT: Weil clojure.contrib.seqverschwunden ist, habe ich meine Antwort mit einem Beispiel einer einfachen Implementierung aktualisiert:

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

Sehr schön! Dies ist die Art von Antwort, die ich erwartet hatte.
John Lawrence Aspden

2
Nicht, dass dies den Wert dieser Antwort beeinflusst, aber seq-utils wurde jetzt nur noch in clojure.contrib.seq geändert.
John Lawrence Aspden

1
@ John, stimmt, ich habe es behoben. Vielen Dank!
Ponzao

Wo bekomme ich clojure.contib.seqClojure 1.6? Keine Bibliothek in Liste: dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k

@ d9k, "Wenn hier ein Namespace clojure.contrib aufgeführt ist, aber keine Migrationsdetails enthält, bedeutet dies, dass sich niemand freiwillig zur Pflege dieses Namespace gemeldet hat." Ich habe eine Beispielimplementierung für hinzugefügt positions.
Ponzao

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

Aber ich möchte Sie davor warnen, mit Indizes herumzuspielen: Meistens wird es weniger idiomatische, unangenehme Clojure produzieren.


Oh schön 'wann'! Ich stimme den Indizes im Allgemeinen zu, aber ich habe eine CSV-Datei und die Namen der Felder befinden sich in der Kopfzeile. Ich möchte das Feld "Feld" aus jeder Zeile abrufen. Ich suche also nach "Feld" in der Kopfzeile und dann nthing die Zeilen. Ich kann mir seltsame Dinge vorstellen, die mit Interleave zu tun haben, aber gibt es eine gute Möglichkeit, keine expliziten Indizes zu verwenden, die lesbar sind?
John Lawrence Aspden

8
Wenn ich diesen Anwendungsfall habe - CSV-Header - habe ich gerade eine Map erstellt, um die Suche durchzuführen (unter der Annahme eindeutiger Spaltenüberschriften). Die Karte ist dann meine Funktion zur Indexsuche. (let [Header-Index (Zipmap-Header-Vektor (iterate inc 0))] ...)
Alex Stoddard

1
Beeindruckend. Sie haben die Frage beantwortet, die ich hätte stellen sollen!
John Lawrence Aspden

3
Nun, ich hätte Alex 'Lösung etwas sehr Ähnliches vorgeschlagen. (-> "colname" Header-Index-Zeile) und Sie haben Ihren Wert.
Cgrand

14

Ab Clojure 1.4 ist clojure.contrib.seq (und damit die positionsFunktion) nicht verfügbar, da ein Betreuer fehlt: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

Die Quelle clojure.contrib.seq/positionsund Abhängigkeit clojure.contrib.seq/indexedist:

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

Hier verfügbar: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions


2
Vielen Dank für die Veröffentlichung dieser Version. Seit 1.2 können Sie auch (iterate inc 0) durch simply (range) ersetzen.
Dribnet

6

Ich habe versucht, meine eigene Frage zu beantworten, aber Brian hat mich mit einer besseren Antwort geschlagen!

(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

Hier ist mein Beitrag, eine loopStruktur zu verwenden und nilbei einem Fehler zurückzukehren.

Ich versuche, Schleifen zu vermeiden, wenn ich kann, aber es scheint für dieses Problem geeignet zu sein.

(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

Ich musste in letzter Zeit mehrmals Indizes finden oder entschied mich dafür, da es einfacher war, als einen anderen Weg zu finden, um das Problem anzugehen. Unterwegs stellte ich fest, dass meine Clojure-Listen nicht die Methode .indexOf (Object object, int start) hatten. Ich habe das Problem folgendermaßen behandelt:

(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

Ich würde mit redu-kv gehen

(defn find-index [pred vec]
  (reduce-kv
    (fn [_ k v]
      (if (pred v)
        (reduced k)))
    nil
    vec))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.