如何过滤序列并保留评估的pred值?

时间:2017-11-16 09:15:35

标签: clojure

这是我多次遇到过的情景,但没有找到适合它的惯用方法......

假设有人想使用自定义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两次。我觉得它太丑了......

想知道是否有更好的方法。非常感谢任何输入!

4 个答案:

答案 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 [..],..}。但这保证了所有的价值都得以保留。