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
Odpowiedzi:
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)
źródło
indexOf
#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
Stuart Halloway dał naprawdę miłą odpowiedź w tym poście 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)
Jeśli chcesz pobrać pierwszą wartość, po prostu użyj
first
wyniku.(first (positions #{"two"} v)) ; -> 1
EDYCJA: Ponieważ
clojure.contrib.seq
zniknął, zaktualizowałem swoją odpowiedź przykładem prostej implementacji:(defn positions [pred coll] (keep-indexed (fn [idx x] (when (pred x) idx)) coll))
źródło
clojure.contib.seq
clojure 1.6? Brak biblioteki na liście: dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Gopositions
.(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.
źródło
Od Clojure 1.4 clojure.contrib.seq (a tym samym
positions
funkcja) 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/positions
i zależnościąclojure.contrib.seq/indexed
jest:(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
źródło
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
źródło
Oto mój wkład, wykorzystujący
loop
strukturę ing i powracającynil
po 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)))))
źródło
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)))))
źródło
Poszedłbym z redukcją kv
(defn find-index [pred vec] (reduce-kv (fn [_ k v] (if (pred v) (reduced k))) nil vec))
źródło