Як знайти індекс елемента у векторі?


83

Будь-які ідеї, які ????повинні бути? Чи є вбудований? Який найкращий спосіб виконати це завдання?

(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

Брайан явно відповідає на це питання, але нижче, cgrand та Alex Stoddard змовляються відповісти на запитання, яке я повинен був задати.
Джон Лоуренс Аспден,

Ніщо не заважає вам задати правильне запитання в окремому питанні :)
Джонатан Бенн,

Відповіді:


136

Вбудований:

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

Якщо вам потрібні ліниві послідовності індексів для всіх збігів:

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
Солодко, дякую Брайане, мій шукач документів не знайшов indexOf, мабуть, тому що це Java. Мені доведеться попрацювати над цим.
Джон Лоуренс Аспден

2
@ Джон: Так. Крапка перед indexOf вказує на взаємодію Java. Він викликає метод 'indexOf' у java.lang.String. java.lang імпортується за замовчуванням. Для отримання додаткових прикладів див. Clojure.org/java_interop
dermatthias

25
Викликається саме векторний indexOfметод, а не String:#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
vemv

44

Стюарт Хеллоуей дав справді гарну відповідь у цій публікації 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)

Якщо ви хочете отримати перше значення, просто використовуйте firstрезультат.

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

EDIT: Оскільки clojure.contrib.seqзник, я оновив свою відповідь прикладом простої реалізації:

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

Дуже хороша! Такої відповіді я очікував.
Джон Лоуренс Аспден

2
Не те, що це впливає на суть цієї відповіді, але seq-utils було змінено просто clojure.contrib.seq.
Джон Лоуренс Аспден

1
@ Джон, правда, я це виправив. Дякую!
ponzao

де взяти clojure.contib.seqв clojure 1.6? У списку немає бібліотеки: dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k

@ d9k, "Якщо тут вказаний простір імен clojure.contrib, але не містить деталей міграції, це означає, що ніхто не зголосився підтримувати цей простір імен." Я додав приклад реалізації для positions.
ponzao

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

Але я хотів би застерегти вас від возиння з індексами: найчастіше це створює менш ідіоматичний, незграбний Clojure.


О, приємно "коли"! Я погоджуюсь з індексами загалом, але у мене є файл csv, і назви полів знаходяться в заголовку, і я хочу отримати поле "поле" з кожного рядка, тому те, що я роблю, шукає "поле" вгору в заголовку, а потім ні в які рядки. Я можу придумати дивні речі, пов’язані з інтерлівеєм, але чи є хороший спосіб, який не використовує явні індекси, які можна прочитати?
Джон Лоуренс Аспден,

8
Коли у мене є такий варіант використання - заголовки csv - я щойно створив карту для пошуку (припускаючи унікальні заголовки стовпців). Тоді карта є моєю функцією для пошуку індексу. (нехай [header-index (zipmap header-vector (iterate inc 0))] ...)
Alex Stoddard

1
Ого. Ви відповіли на питання, яке я повинен був задати!
Джон Лоуренс Аспден,

3
Ну, я б запропонував щось дуже схоже на рішення Алекса. (-> рядок заголовка-індексу "colname") і у вас є своє значення.
cgrand

14

Починаючи з Clojure 1.4 clojure.contrib.seq (і, отже, positionsфункція) недоступний, оскільки в ньому відсутній супровідник: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

Джерелом clojure.contrib.seq/positionsі залежністю clojure.contrib.seq/indexedє:

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

Доступно тут: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions


2
Дякуємо за розміщення цієї версії. Починаючи з 1.2, ви також можете замінити (повторити 0) на просто (діапазон).
dribnet

6

Я намагався відповісти на власне запитання, але Брайан побив мене кращою відповіддю!

(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

Ось мій внесок, використовуючи loopвведену структуру та повертаючись nilу разі відмови.

Я намагаюся уникати циклів, коли можу, але, здається, це підходить для цієї проблеми.

(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

Нещодавно мені довелося кілька разів знаходити індекси, а точніше, я вирішив, оскільки це було простіше, ніж з’ясувати інший спосіб підходу до проблеми. По дорозі я виявив, що в моїх списках Clojure не було методу .indexOf (Object object, int start). Я вирішив проблему так:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.