Clojure中如何将partition生成的窗口集合传递给其他函数处理
滑动窗口参数传递实现
你需要结合map和apply两个函数完成需求,apply的作用是将集合内的元素拆分为独立参数传入目标函数,刚好匹配你bar函数接收3个入参的要求,map用来遍历所有滑动窗口执行处理逻辑。
首先给bar补一个简易实现方便验证效果:
(def foo [:a :b :c :d :e]) ;; 示例:将三个输入拼接为字符串 (defn bar [start next end] (str start "-" next "-" end))
你的faz函数可以按以下方式实现:
(defn faz [coll] (->> coll ;; 生成3元素滑动窗口 (partition 3 1) ;; 遍历每个窗口,拆分参数传入bar (map #(apply bar %))))
执行测试:
(faz foo) ;; 返回结果:(":a-:b-:c" ":b-:c-:d" ":c-:d-:e")
如果你不需要收集所有窗口的处理结果,只需要执行打印、写入这类副作用操作,把map替换为doseq即可:
(defn faz [coll] (doseq [window (partition 3 1 coll)] (apply bar window)))
reduce、apply相关实现思路
apply的核心逻辑是集合参数拆包,不受参数数量限制,只要集合长度和目标函数的入参数量匹配就能使用,并非只能处理2个元素的场景。比如你有一个接收5个参数的函数,就可以写(apply func [a b c d e]),等价于(func a b c d e)。reduce的核心逻辑是累计迭代,遍历集合的过程中可以自定义维护状态,你也可以直接用reduce实现滑动窗口处理,不需要提前调用partition生成所有窗口,更适合超大集合、流式处理的低内存需求场景。3元素滑动窗口的reduce实现示例如下:
(defn faz-with-reduce [coll] (reduce (fn [current-window ele] (let [new-window (conj current-window ele)] (if (= 3 (count new-window)) (do ;; 窗口填充完成,调用bar处理 (apply bar new-window) ;; 移除队首元素,进入下一轮迭代 (subvec new-window 1)) new-window))) ;; 初始状态为空窗口 [] coll))
你之前看到的reduce示例大多对应(partition 2 1)的效果,是因为双元素滑动窗口的reduce实现更简洁:只需要把上一个元素作为累计状态,每次迭代用「上一个元素+当前元素」调用处理函数即可,代码示例:
;; 双元素处理函数 (defn bar2 [a b] (str a "->" b)) (reduce (fn [last-ele ele] (bar2 last-ele ele) ele) (first foo) (rest foo))
内容的提问来源于stack exchange,提问作者JustBul
相关产品推荐
相关产品推荐

