我有一个序列s
和一个索引列表indexes
。如何仅保留通过索引提供的项目?
简单示例:
(filter-by-index '(a b c d e f g) '(0 2 3 4)) ; => (a c d e)
我的用例:
(filter-by-index '(c c# d d# e f f# g g# a a# b) '(0 2 4 5 7 9 11)) ; => (c d e f g a b)
答案 0 :(得分:24)
您可以使用keep-indexed
:
(defn filter-by-index [coll idxs]
(keep-indexed #(when ((set idxs) %1) %2)
coll))
使用显式recur和lazy-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))))))
答案 1 :(得分:13)
制作包含与索引相结合的项目的向量列表
(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])
过滤此列表
lojure.core=> (def filtered (filter #(#{1 3 5 7} (second % )) with-indexes))
#'clojure.core/filtered
clojure.core=> filtered
([b 1] [d 3] [f 5])
然后删除索引。
clojure.core=> (map first filtered)
(b d f)
然后我们将它与“thread last”宏一起用线程
(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)
故事的寓意是,将其分解为小的独立部分,测试它们,然后将它们组合成一个工作函数。
答案 2 :(得分:6)
我喜欢Jonas的答案,但这两个版本都不适用于无限的索引序列:第一个尝试创建一个无限集,后者在layering too many unrealized lazy sequences之间进入堆栈溢出。为了避免这两个问题,你需要做更多的手工工作:
(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))
使用此版本,coll
和idxs
都可以是无限的,您仍然可以没有问题:
user> (nth (filter-by-index (range) (iterate #(+ 2 %) 0)) 1e6)
2000000
编辑:不要试图挑出Jonas的答案: none 其他解决方案适用于无限索引序列,这就是我觉得需要解决方案的原因。
答案 3 :(得分:6)
最简单的解决方案是使用map
:
(defn filter-by-index [coll idx]
(map (partial nth coll) idx))
答案 4 :(得分:1)
我有一个类似的用例,并提出了另一个简单的解决方案。这个期待矢量。
我已经更改了函数名称以匹配其他类似的clojure函数。
(defn select-indices [coll indices]
(reverse (vals (select-keys coll indices))))
答案 5 :(得分: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]
答案 6 :(得分: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]
答案 7 :(得分:0)
我知道这不是被问到的,但在阅读完这些答案之后,我意识到在我自己的个人用例中,我真正想要的是基本上用掩码过滤。
所以这是我的看法。希望这会帮助其他人。
(defn filter-by-mask [coll mask]
(filter some? (map #(if %1 %2) mask coll)))
(defn make-errors-mask [coll]
(map #(nil? (:error %)) coll))
用法
(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")