假设我有一个像这样的元组列表:
[["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)
答案 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&mapv
和filterv
替换我的实现#39;单次迭代实现。