单次迭代中的多个过滤器

时间:2017-02-28 19:49:26

标签: filter clojure functional-programming

假设我有一个像这样的元组列表:

[["type_2" "val_x"] ["type_1" "val_y"] ["type_1" "val_z"]]

我想过滤它们,以便我有两个单独的集合:

[["type_2" "val_x"]] 

[["type_1" "val_y"] ["type_1" "val_z"]]

我可以运行两次过滤器。我想知道是否可以通过函数式编程在单次迭代中实现相同的结果?

这是所需的界面:

(multiple-filter predicate_fn_1 predicate_fn_2 coll)

2 个答案:

答案 0 :(得分:3)

虽然(vals (group-by first...在您的情况下可以正常工作,但它不是通用的。以下是应用多个过滤器的变体(许多可能的变体之一):

(defn classify [items & preds]
  (loop [[x & xs :as items] items
         res (repeat (count preds) [])]
    (if (empty? items)
      res
      (recur xs 
             (mapv #(if (% x) (conj %2 x) %2) preds res)))))

在repl中:

user> (classify [[:a 10] [:a 20] [:b 30] [:d 2] [:c 40] [:d 1]]
                #(= (first %) :a)
                #(= (first %) :b)
                #(= (first %) :d))
[[[:a 10] [:a 20]] [[:b 30]] [[:d 2] [:d 1]]]

或与reduce相同:

(defn classify [items & preds]
  (reduce (fn [res x] (mapv #(if (% x) (conj %2 x) %2) preds res))
          (repeat (count preds) [])
          items))

答案 1 :(得分:1)

@leetwinski的classify函数无法满足您所需的界面;例如,这是一个合规的实现:

(defn multiple-filter [& preds-and-coll]
  (let [[preds coll] ((juxt drop-last last) preds-and-coll)]
    (mapv #(filterv % coll) preds)))

示例:

(multiple-filter (comp #{"type_1"} first)
                 (comp #{"type_2"} first)
                 [["type_2" "val_x"] ["type_1" "val_y"] ["type_1" "val_z"]])
;;=> [[["type_1" "val_y"] ["type_1" "val_z"]] [["type_2" "val_x"]]]

我还没有将其作为单个迭代实现,因为这会使这个答案复杂化并且不会影响算法的复杂性,但可以使用@ {leetwinski&mapvfilterv替换我的实现#39;单次迭代实现。