【问题标题】:multiple filters in a single iteration一次迭代中的多个过滤器
【发布时间】:2017-03-01 04:43:35
【问题描述】:

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

[["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)

【问题讨论】:

  • (vals (group-by first [["type_2" "val_x"] ["type_1" "val_y"] ["type_1" "val_z"]])) 应该做你想做的事
  • @m33lky 能否请您将代码块移动到它们自己的行中并在行首添加四个空格以使其成为代码块,然后从它们周围删除` `。我通常会修复这些格式问题,但 SO 存在问题,我无法使用其他待处理的编辑来编辑问题,因此我无法为您修复此格式。
  • @ArthurUlfeldt 将所有内容放在代码块中而不是刻度中

标签: filter clojure functional-programming


【解决方案1】:

虽然 (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)))))

在回复中:

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))

【讨论】:

  • 你也可以写(apply classify [[:a 10] [:a 20] [:b 30] [:d 2] [:c 40] [:d 1]] (map #(comp #{%} first) [:a :b :d]))。
  • @SamEstep 为什么不将其添加为单独的答案?
  • @m33lky 因为我的评论只是对函数使用的说明,与实现无关。但是,我也相信可以改进实现,所以我也添加了自己的答案。
【解决方案2】:

@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"]]]

我没有将其实现为单次迭代,因为这会使答案复杂化并且不会影响算法的复杂性,但请随意将我使用 mapv 和 filterv 的实现替换为 @leetwinski 的单次迭代实现。

【讨论】:

  • 所以实际上是(count preds) 传递集合?虽然问题(至少我不明白)是关于一次通过多个过滤器
  • @leetwinski 是的,我在回答中部分解决了这个问题:在我的实现中,外循环遍历preds,内循环遍历coll,而在您的实现中,外循环遍历items,内部循环遍历preds。它不会影响算法的复杂性,所以我保持原样,但如果需要的话,很容易在你的实现中交换。
  • 哦。你说的对。我想这个更好。
猜你喜欢
  • 2020-12-23
  • 2013-10-04
  • 2021-10-05
  • 2015-10-04
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
相关资源
最近更新 更多