Làm cách nào để tìm chỉ mục của một mục trong một vectơ?


83

Bất kỳ ý tưởng những gì ????nên được? Có được xây dựng trong không? Cách tốt nhất để hoàn thành nhiệm vụ này là gì?

(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 rõ ràng là câu trả lời cho câu hỏi này, nhưng dưới đây, cgrand và Alex Stoddard cố gắng trả lời câu hỏi mà tôi nên hỏi.
John Lawrence Aspden

Không có gì ngăn bạn đặt câu hỏi chính xác trong một câu hỏi riêng biệt :)
Jonathan Benn

Câu trả lời:


134

Được xây dựng trong:

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

Nếu bạn muốn có một seq lười biếng của các chỉ số cho tất cả các trận đấu:

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
Thật tuyệt, cảm ơn Brian, người tìm kiếm tài liệu của tôi đã không tìm thấy indexOf, có lẽ vì đó là Java. Tôi sẽ phải làm việc trên nó.
John Lawrence Aspden

2
@John: Vâng. Dấu chấm trước indexOf biểu thị tương tác Java. Nó gọi phương thức 'indexOf' trong java.lang.String. java.lang được nhập theo mặc định. Để biết thêm ví dụ, hãy xem clojure.org/java_interop
dermatthias

25
Đó là của vector indexOfphương pháp đó mà được gọi là, không Chuỗi của:#<Method public int clojure.lang.APersistentVector.indexOf(java.lang.Object)>
vemv

44

Stuart Halloway đã đưa ra một câu trả lời thực sự tuyệt vời trong bài đăng này 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)

Nếu bạn muốn lấy giá trị đầu tiên, chỉ cần sử dụng firsttrên kết quả.

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

CHỈNH SỬA: Vì clojure.contrib.seqđã biến mất nên tôi đã cập nhật câu trả lời của mình bằng một ví dụ về cách triển khai đơn giản:

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

Rất đẹp! Đây là loại câu trả lời tôi đã mong đợi.
John Lawrence Aspden

2
Không phải là nó ảnh hưởng đến giá trị của câu trả lời này, nhưng seq-utils đã được thay đổi ngay bây giờ clojure.contrib.seq.
John Lawrence Aspden

1
@John, đúng, tôi đã sửa nó. Cảm ơn!
ponzao

lấy clojure.contib.seqở đâu trong clojure 1.6? Không có thư viện nào trong danh sách: dev.clojure.org/display/community/Where+Did+Clojure.Contrib+Go
d9k

@ d9k, "Nếu không gian tên clojure.contrib được liệt kê ở đây nhưng không có chi tiết di chuyển, điều đó có nghĩa là không ai tình nguyện duy trì không gian tên đó." Tôi đã thêm một triển khai ví dụ cho positions.
ponzao

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

Nhưng tôi muốn cảnh báo bạn không nên loay hoay với các chỉ số: thường thì nó sẽ tạo ra Clojure ít thành ngữ và vụng về hơn.


Oh tốt 'khi nào'! Tôi đồng ý về các chỉ số nói chung, nhưng tôi có một tệp csv và tên của các trường nằm trong tiêu đề và tôi muốn lấy trường "trường" từ mỗi hàng, vì vậy điều tôi đang làm là tìm "trường" trong tiêu đề, rồi xếp thứ tự các hàng. Tôi có thể nghĩ ra những điều kỳ lạ để làm với interleave, nhưng có cách nào hay ho mà không sử dụng các chỉ số rõ ràng có thể đọc được không?
John Lawrence Aspden

8
Khi tôi có trường hợp sử dụng đó - tiêu đề csv - tôi vừa tạo một bản đồ để thực hiện tra cứu (giả sử các tiêu đề cột duy nhất). Bản đồ sau đó chức năng của tôi để thực hiện tra cứu chỉ mục. (let [header-index (zipmap header-vector (iterate inc 0))] ...)
Alex Stoddard

1
Chà. Bạn đã trả lời câu hỏi mà tôi nên hỏi!
John Lawrence Aspden

3
Chà, tôi đã đề xuất một cái gì đó rất dễ hiểu cho giải pháp của Alex. (-> hàng tiêu đề-chỉ mục "colname") và bạn có giá trị của mình.
cgrand

14

Kể từ khi Clojure 1.4, clojure.contrib.seq (và do đó là positionschức năng) không khả dụng vì nó thiếu người bảo trì: http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go

Nguồn clojure.contrib.seq/positionsvà sự phụ thuộc của nó clojure.contrib.seq/indexedlà:

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

Có sẵn tại đây: http://clojuredocs.org/clojure_contrib/clojure.contrib.seq/positions


2
Cảm ơn vì đã đăng phiên bản này. Vì 1.2, bạn cũng có thể thay thế (lặp lại khoảng 0) bằng (phạm vi).
dribnet

6

Tôi đã cố gắng trả lời câu hỏi của chính mình, nhưng Brian đã đánh bại tôi với câu trả lời hay hơn!

(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

Đây là đóng góp của tôi, sử dụng loopcấu trúc ing và trả lại khi nilthất bại.

Tôi cố gắng tránh các vòng lặp khi tôi có thể, nhưng nó có vẻ phù hợp cho vấn đề này.

(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

Gần đây tôi đã phải tìm các chỉ mục nhiều lần hoặc đúng hơn là tôi đã chọn vì nó dễ hơn là tìm ra một cách khác để tiếp cận vấn đề. Trong quá trình thực hiện, tôi phát hiện ra rằng danh sách Clojure của mình không có phương thức .indexOf (Đối tượng đối tượng, int start). Tôi đã giải quyết vấn đề như vậy:

(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

Tôi sẽ đi với giảm-kv

(defn find-index [pred vec]
  (reduce-kv
    (fn [_ k v]
      (if (pred v)
        (reduced k)))
    nil
    vec))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.