聚合具有中间值的传感器

Aggregating transducers with intermediate values

我仍在努力更好地理解如何在 clojure 中使用转换器。在这里,我对应用聚合传感器感兴趣,例如 https://github.com/cgrand/xforms 中的传感器,但在每一步都报告计算的中间值。

例如下面的表达式

(sequence (x/into #{}) [1 2 3])

产量(#{1 2 3}),这只是减少的最终值。现在,我会对给定类似

的传感器 xf-incremental 感兴趣
(sequence (comp xf-incremental (x/into #{})) [1 2 3])

产量 (#{1} #{1 2} #{1 2 3}).

我对此感兴趣的原因是我想报告一个指标的中间值,该指标汇总了处理值的历史记录。

知道如何以通用方式执行此类操作吗?

编辑:将 (x/into #{}) 视为聚合结果的任意转换器。更好的例子可能是 x/avg 或 (x/reduce +) 我期望

(sequence (comp xf-incremental x/avg) [1 2 3])
(sequence (comp xf-incremental (x/reduce +)) [1 2 3])

分别为return(1 3/2 2)(1 3 6)

编辑 2:另一种表达方式是,我想要一个执行减少功能的传感器,并且 return 在每一步都有累加器,它也可以重用所有可用的传感器,所以我不需要重写基本功能。

使用clojure的解决方案。core/reductions

您不需要传感器来执行您要求的计算。您要查看 reduce 的所有中间结果的函数称为 reductions 并为它提供 conj 和一个空集作为参数:

(rest (reductions conj #{} [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})

rest 删除第一个空集,因为这是您在原始问题中请求的输出。

这里建立结果的函数是conj,我们称它为阶跃函数transducer 是一个函数,它将阶跃函数作为输入,returns 一个新的阶跃函数作为输出。因此,如果我们想将 reductions 与转换器结合使用,我们只需将转换器应用于 conj:

(def my-transducer (comp (filter odd?)
                         (take 4)))

(dedupe (reductions (my-transducer conj) #{} (range)))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})

dedupe 只是为了删除等于前面元素的元素。如果您不想这样做,可以将其删除。在这种情况下,您会得到以下结果,因为这就是过滤传感器的工作原理:

(reductions (my-transducer conj) #{} (range)))
;; => (#{} #{} #{1} #{1} #{1 3} #{1 3} #{1 3 5} #{1 3 5} #{7 1 3 5})

基于传感器的解决方案使用 net.cgrand.xforms/reductions

显然,xforms 库中还有 reductionstransducer 版本,它更接近您的初始代码:

(require '[net.cgrand.xforms :as xforms])

(rest (sequence (xforms/reductions conj #{}) [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})

这个 xforms/reductions 转换器可以与其他使用 comp 的转换器组成,例如过滤奇数并取其中的前四个:

(sequence (comp (filter odd?)
                (take 4)
                (xforms/reductions conj #{}))

          (range))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})

在这种情况下,您不需要 dedupe。也可以使用 xforms/reductions 的其他阶跃函数,例如+:

(sequence (comp (filter odd?)
                (take 10)
                (xforms/reductions + 0)
                (filter #(< 7 %)))

          (range))
;; => (9 16 25 36 49 64 81 100)