2011-12-27 29 views
21

Với Clojure, làm cách nào để tìm chỉ mục đầu tiên có giá trị dương trong vector này [-1 0 3 7 9]?Tìm chỉ mục của một phần tử khớp với vị từ trong Clojure?

Tôi biết bạn có thể nhận được kết quả đầu tiên của một cái gì đó khá thanh lịch với firstfilter:

(first (filter pos? [-1 0 99 100 101]))

Mã này trả về giá trị 99. Câu trả lời tôi muốn là chỉ số là 2.

+0

Xem tại đây: http://stackoverflow.com/questions/4830900/how-do-i-find-the-index-of-an-item-in-a-vector – nimrodm

+0

Câu hỏi của tôi hoàn toàn khác. Tôi đã chỉnh sửa tiêu đề của mình để phản ánh điều này. –

Trả lời

37

Sử dụng keep-indexed bạn có thể nhận được một chuỗi các chỉ số mà một vị được thỏa mãn:

(defn indices [pred coll] 
    (keep-indexed #(when (pred %2) %1) coll)) 

Với chức năng đơn giản này, bạn sẽ giải quyết vấn đề của bạn với các biểu hiện

user=> (first (indices pos? [-1 0 99 100 101])) 
2 

Lưu ý rằng, do sự lười biếng của keep-indexed (và indices), toàn bộ trình tự không cần phải được thực hiện để không thực hiện các phép tính ngoại lai.

+0

rất hay. đó là những gì tôi đang tìm kiếm. –

+0

Công trình này tuyệt vời. (Khi tôi đào sâu vào nó, tôi nhận thấy rằng 'keep-indexed' bao gồm ** non-nil ** (bao gồm các kết quả' false'). Tôi không biết lý do cho điều này.) –

1
(defn pred-idx [pred [idx hist] cur] 
    (if (pred cur) 
    [(inc idx) (conj hist idx)] 
    [(inc idx) hist])) 

(defn idx-filter [pred col] 
    (second (reduce (partial pred-idx pred) [0 []] col))) 

(first (idx-filter pos? [-1 0 99 100 101])) 
2 

Không chắc chắn nếu điều này là tốt hơn, nhưng nó hoạt động. Tôi nghĩ rằng nó buộc đánh giá toàn bộ chuỗi mặc dù, và nếu bạn cần tất cả các chỉ số sẽ tốt hơn. Điều chính xác để làm là có thể biến nó thành một chuỗi lười biếng bằng cách nào đó, nhưng tôi đã làm cho buổi tối.

+0

Tôi muốn một cái gì đó có thể xử lý ví dụ của tôi. Tìm chỉ mục của giá trị dương đầu tiên trong bộ sưu tập. –

+0

Xin lỗi, không đọc rõ điều đó. – Bill

+0

lỗi của tôi tiêu đề của tôi không rõ ràng –

0

Hãy thử điều này:

(defn first-index 
    ([pred coll] (first-index coll pred 0)) 
    ([pred coll idx] 
    (cond (= coll '()) -1 
      (pred (first coll)) idx 
      :else (recur pred (rest coll) (inc idx))))) 

Và sử dụng nó như thế này:

(defn is-pos? [x] 
    (> x 0)) 

(first-index is-pos? [-1 0 3 7 9]) 

Nó trả về chỉ số zero-dựa trên các yếu tố đầu tiên mà đáp ứng các vị ngữ (is-pos? trong ví dụ), hoặc -1 nếu không có phần tử nào khớp với vị từ.

+1

Hàm này sẽ chỉ trả về -1 nếu được thông qua 'nil' một cách rõ ràng, bởi vì' (phần còn lại x) 'không bao giờ là nil cho bất kỳ' x' nào. Bạn nên gọi 'seq' trên bộ sưu tập trước khi kiểm tra nó cho nil. Ngoài ra, '[pred coll]' sẽ là một thứ tự đối số thân thiện hơn '[coll pred]' - cf. Ví dụ: 'map' và' filter'. – amalloy

+0

công trình này (với đề xuất của amalloy), nhưng phiên bản sử dụng giữ lập chỉ mục đơn giản hơn rất nhiều. – Gert

+0

Ở đó, tôi đã chỉnh sửa nó theo nhận xét của @ amalloy. Đến từ một nền của Đề án, thật kỳ lạ là không!= '() trong Clojure –

3
(defn first-pos [x] 
    (loop [arr x n 0] 
    (if (pos? (first arr)) 
    n 
    (recur (next arr) (inc n))))) 

Đây là ví dụ điển hình về việc sử dụng đệ quy đuôi mạnh mẽ của lập trình hàm.

+0

Không thành công với 'NullPointerException' nếu không có phần tử dương trong danh sách; OP cũng đã yêu cầu kết quả của một biến vị ngữ tùy ý, không chỉ 'pos? ' –

1
(first (filter #(not (nil? %)) (map #(when (pos? %1) %2) [-1 1 0 99 100 101] (range)))) 

Bản đồ có thể lấy một hoặc nhiều bộ sưu tập và trả về một danh sách, đặt điều kiện trên bản đồ và lọc nil.

Các vấn đề liên quan