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
John Lawrence Aspden
quelle
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)
Brian Carper
quelle
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/[email protected]/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))
ponzao
quelle
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.

cgrand
quelle
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

lsh
quelle
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
John Lawrence Aspden
quelle
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)))))
Josh.F
quelle
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)))))
Joshua
quelle
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))
overmind1
quelle