【发布时间】:2016-07-16 04:10:49
【问题描述】:
在 Clojure 中,我想找到多次归约的结果,同时只使用一次序列。在 Java 中,我会执行以下操作:
double min = Double.MIN_VALUE;
double max = Double.MAX_VALUE;
for (Item item : items) {
double price = item.getPrice();
if (price > min) {
min = price;
}
if (price < max) {
max = price;
}
}
在 Clojure 中,我可以通过使用循环和递归来做很多相同的事情,但它不是很可组合 - 我想做一些事情,让您可以根据需要添加其他聚合函数。
我为此编写了以下函数:
(defn reduce-multi
"Given a sequence of fns and a coll, returns a vector of the result of each fn
when reduced over the coll."
[fns coll]
(let [n (count fns)
r (rest coll)
initial-v (transient (into [] (repeat n (first coll))))
fns (into [] fns)
reduction-fn
(fn [v x]
(loop [v-current v, i 0]
(let [y (nth v-current i)
f (nth fns i)
v-new (assoc! v-current i (f y x))]
(if (= i (- n 1))
v-new
(recur v-new (inc i))))))]
(persistent! (reduce reduction-fn initial-v r))))
这可以通过以下方式使用:
(reduce-multi [max min] [4 3 6 7 0 1 8 2 5 9])
=> [9 0]
我很欣赏它没有以最惯用的方式实现,但主要问题是它的速度大约是一次减少一个的 10 倍。这对于在 seq 执行大量 IO 的情况下执行大量归约可能很有用,但肯定会更好。
现有的 Clojure 库中有什么东西可以满足我的需求吗?如果没有,我的功能哪里出错了?
【问题讨论】:
-
你读过传感器吗?如果是这样,他们会感到困惑吗?如果没有,建议使用。
-
@AWebb
juxt看起来很完美......但不是必需的,对吧?我的理解是,传感器允许在不创建中间序列的情况下进行一系列单独的reduce调用,这就是我的目标。 -
@Mars 在系列中,就像在构图中一样,是的。我并没有立即看到并列,就像并列一样,干净,但遗憾的是,我还没有在编写自己的传感器方面玩太多。
-
@Frank C. 不,现在才开始研究它们。我之前听说过它们,但我认为它们更多是为了有效地将这些操作链接在一起,而不是让你做一些完全不同的事情。正如我在 cmets 对 leetwinski 的回答中所指出的那样,也许性能提升对于实现优雅同时仍然以更幼稚的方法保持同等速度是必要的。
标签: clojure functional-programming reduce