2011-10-12 32 views

Trả lời

13

lập danh sách các vectơ chứa các mục kết hợp với các chỉ số,

(def with-indexes (map #(vector %1 %2) ['a 'b 'c 'd 'e 'f] (range))) 
#'clojure.core/with-indexes 
with-indexes 
([a 0] [b 1] [c 2] [d 3] [e 4] [f 5]) 

lọc danh sách này

lojure.core=> (def filtered (filter #(#{1 3 5 7} (second %)) with-indexes)) 
#'clojure.core/filtered 
clojure.core=> filtered 
([b 1] [d 3] [f 5]) 

sau đó loại bỏ các chỉ số.

clojure.core=> (map first filtered)           
(b d f) 

thì chúng ta thread nó cùng với các "chủ đề cuối cùng" vĩ mô

(defn filter-by-index [coll idxs] 
    (->> coll 
     (map #(vector %1 %2)(range)) 
     (filter #(idxs (first %))) 
     (map second))) 
clojure.core=> (filter-by-index ['a 'b 'c 'd 'e 'f 'g] #{2 3 1 6}) 
(b c d g) 

Các đạo đức của câu chuyện là, phá vỡ nó thành các phần độc lập nhỏ, kiểm tra chúng, sau đó soạn chúng thành một chức năng làm việc .

+0

Tuyệt vời, thx! Tôi đã có một cái gì đó như thế, nhưng tôi không thể tìm ra để sử dụng "phạm vi" đúng cách. – qollin

+0

Tôi đang cuộn nó thành một funciton đẹp, chỉnh sửa sớm :) –

+0

ohh và lưu ý rằng tôi đã chuyển danh sách các chỉ mục cho một vectơ các chỉ mục. Điều này là do bộ có thể được sử dụng như một chức năng lọc. –

23

Bạn có thể sử dụng keep-indexed:

(defn filter-by-index [coll idxs] 
    (keep-indexed #(when ((set idxs) %1) %2) 
       coll)) 

Một phiên bản sử dụng tái diễn rõ ràng và lười biếng-seq:

(defn filter-by-index [coll idxs] 
    (lazy-seq 
    (when-let [idx (first idxs)] 
    (if (zero? idx) 
     (cons (first coll) 
      (filter-by-index (rest coll) (rest (map dec idxs)))) 
     (filter-by-index (drop idx coll) 
         (map #(- % idx) idxs)))))) 
0
(defn filter-by-index [seq idxs] 
    (let [idxs (into #{} idxs)] 
    (reduce (fn [h [char idx]] 
       (if (contains? idxs idx) 
       (conj h char) h)) 
      [] (partition 2 (interleave seq (iterate inc 0)))))) 

(filter-by-index [\a \b \c \d \e \f \g] [0 2 3 4]) 
=>[\a \c \d \e] 
5

Tôi thích câu trả lời của Jonas, nhưng không phiên bản nào hoạt động tốt cho chuỗi vô hạn: lần đầu tiên cố gắng tạo một tập hợp vô hạn và sau đó chạy vào ngăn xếp ngăn xếp layering too many unrealized lazy sequences trên đầu trang của nhau. Để tránh cả hai vấn đề bạn phải làm công việc nhẹ thủ công hơn:

(defn filter-by-index [coll idxs] 
    ((fn helper [coll idxs offset] 
    (lazy-seq 
     (when-let [idx (first idxs)] 
     (if (= idx offset) 
      (cons (first coll) 
       (helper (rest coll) (rest idxs) (inc offset))) 
      (helper (rest coll) idxs (inc offset)))))) 
    coll idxs 0)) 

Với phiên bản này, cả hai collidxs có thể là vô hạn và bạn vẫn sẽ không có vấn đề:

user> (nth (filter-by-index (range) (iterate #(+ 2 %) 0)) 1e6) 
2000000 

Edit: không cố gắng để chỉ ra câu trả lời của Jonas: none của các giải pháp khác làm việc cho chuỗi vô hạn, đó là lý do tại sao tôi cảm thấy một giải pháp mà là cần thiết.

+0

Tôi tự hỏi đó là một trường hợp cạnh xa hơn, một chuỗi các chỉ số vô hạn để giữ, hoặc các chỉ số không theo thứ tự tăng dần đơn điệu. –

+0

@AlexTaggart tốt, vì không thể phục vụ cho cả hai tôi đoán bạn phải đưa ra quyết định. Sự lười biếng có vẻ quan trọng hơn đối với tôi, như một phần của triết lý Clojure nói chung, nhưng đối với một trường hợp cụ thể của vấn đề nó có thể dễ dàng sai. – amalloy

0
=> (defn filter-by-index [src indexes] 
    (reduce (fn [a i] (conj a (nth src i))) [] indexes)) 

=> (filter-by-index '(a b c d e f g) '(0 2 3 4)) 
[a c d e] 
6

Giải pháp đơn giản nhất là sử dụng map:

(defn filter-by-index [coll idx] 
    (map (partial nth coll) idx)) 
1

Tôi đã có một trường hợp sử dụng tương tự và đã đưa ra một giải pháp dễ dàng. Điều này hy vọng vectơ.

Tôi đã thay đổi tên hàm để khớp với các hàm clojure tương tự khác.

(defn select-indices [coll indices] 
    (reverse (vals (select-keys coll indices)))) 
0

Tôi biết đây không phải là những gì được hỏi, nhưng sau khi đọc những câu trả lời này, tôi nhận ra trong trường hợp sử dụng cá nhân của riêng tôi.

Vì vậy, đây là nhận của tôi. Hy vọng rằng điều này sẽ giúp người khác.

(defn filter-by-mask [coll mask] 
    (filter some? (map #(if %1 %2) mask coll))) 

(defn make-errors-mask [coll] 
    (map #(nil? (:error %)) coll)) 

Cách sử dụng

(let [v [{} {:error 3} {:ok 2} {:error 4 :yea 7}] 
    data ["one" "two" "three" "four"] 
    mask (make-errors-mask v)] 
    (filter-by-mask data mask)) 

; ==> ("one" "three") 
Các vấn đề liên quan