这是我多次遇到过的情景,但没有找到适合它的惯用方法......
假设有人想使用自定义self-pred
函数来过滤seq。此self-pred
函数返回nil
表示不需要的元素,以及有用元素的有用信息。希望保留这些所需元素的评估self-pred
值。
我的一般解决方案是:
;; self-pred is a pred function which returns valuable info
;; in general, they are unique and can be used as key
(let [new-seq (filter self-pred aseq)]
(zipmap (map self-pred new-seq) new-seq))
基本上,它是在所有想要的元素上调用self-pred
两次。我觉得它太丑了......
想知道是否有更好的方法。非常感谢任何输入!
答案 0 :(得分:5)
在这些情况下,您可以使用keep
,但您必须更改“谓词”功能,以便为每个项目返回所需的完整信息或nil
。
例如:
(keep (fn [item]
(when-let [tested (some-test item)]
(assoc item :test-output tested))) aseq)
答案 1 :(得分:4)
我使用这种代码段:
(keep #(some->> % self-pred (vector %)) data)
像这样:
user> (keep #(some->> % rseq (vector %)) [[1 2] [] [3 4]])
;;=> ([[1 2] (2 1)] [[3 4] (4 3)])
或者如果你想要更详细的结果:
user> (keep #(some->> % rseq (hash-map :data % :result)) [[1 2] [] [3 4]])
;;=> ({:result (2 1), :data [1 2]} {:result (4 3), :data [3 4]})
答案 2 :(得分:1)
我不会为keep
而烦恼,但只会使用普通地图&像这样过滤:
(def data (range 6))
(def my-pred odd?)
(defn zip [& colls] (apply map vector colls)) ; like Python zip
(defn filter-with-pred
[vals pred]
(filter #(first %)
(zip (map pred vals) vals)))
(println (filter-with-pred data my-pred))
结果:
([true 1] [true 3] [true 5])
答案 3 :(得分:-1)
如果self-pred保证不会为不同的值创建重复的密钥,那么我将达到reduce(因为关联相同的密钥两次将覆盖原始密钥值对):
(reduce #(if-let [k (self-pred %2)]
(assoc %1 k %2)
%1)
{}
aseq)
否则我们可以使用分组来推动类似的结果:
(dissoc (group-by self-pred aseq) nil)
虽然不相同,因为值将在向量中:{k1 [v1 ..],k2 [..],..}。但这保证了所有的价值都得以保留。