[英]Clojure: Executing an operation n times using the output as input of next operation (a-la reduce)
I want to execute a given amount of time a certain operation (eg, generating a tribe). 我想执行给定时间的某个操作(例如,生成部落)。 Each time I would like to use the output of the previous iteration as input of the next one. 每次我想将上一次迭代的输出用作下一次迭代的输入时。
I am achieving it by doing a dummy reduce on collection of n elements, I then consider only the accumulator and throw away the element from the collection. 我通过对n个元素的集合进行虚拟减少来实现它,然后仅考虑累加器,并从集合中丢弃该元素。
(defn generate-game [world n-tribes]
(let [ game (create-game world)
game (reduce (fn [acc, _] (:game (generate-tribe acc))) game (repeat n-tribes :just_something))]
game))
I assume there is a much better way to do that. 我认为有一个更好的方法来做到这一点。 Can you help me finding it? 你能帮我找到它吗?
If it's the same function repeated n-tribes
times, then using iterate and getting the n-tribes
'th element should work: 如果它是重复n-tribes
时间的相同函数,那么使用迭代并获得n-tribes
的元素应该工作:
(defn generate-game [world n-tribes]
(let [ game (create-game world)
game (nth (iterate generate-tribe game) n-tribes)]
game))
Remember that iterate
creates a lazy sequence so nothing will be calculated until you request it. 请记住, iterate
创建一个惰性序列,因此在您请求之前不会计算任何东西。
Another option is applying comp to the list of functions, after all it's a simple function composition: 另一种选择是将comp应用于函数列表,毕竟它是一个简单的函数组合:
(generate-tribe (generate-tribe .... (generate-tribe game) ....))
n-tribes times
So something like: 所以类似于:
(defn generate-game [world n-tribes]
(let [ game (create-game world)
game ((apply comp (repeat n-tribes generate-tribe)) game)]
game))
expresses exactly that idea. 表达了这个想法。
Not a Clojure expert, but I would expect 不是Clojure专家,但我希望如此
(defn generate-game [world n-tribes]
(nth (iterate generate-tribe (create-game world)) n-tribes))
or (less terse) 或者(简洁)
(defn generate-game [world n-tribes]
(let [game (create-game world)]
(nth (iterate generate-tribe game) n-tribes)))
to work 上班
The method used in the question is fine, but use range instead 问题中使用的方法很好,但是使用范围代替
(defn generate-game [world n-tribes]
(reduce (fn [acc _] (:game (generate-tribe acc)))
(create-game world)
(range n-tribes)))
Since range objects know how to intelligently reduce themselves, this will get turned into a loop. 由于范围对象知道如何智能地还原自身,因此这将变成一个循环。 This is the reduce
method of range: 这是范围的reduce
方法:
public Object reduce(IFn f, Object start) {
Object ret = f.invoke(start,n);
for(int x = n+1;x < end;x++)
ret = f.invoke(ret, x);
return ret;
}
If your game state is going to wind up in an atom anyway then you could also consider dotimes
to update it. 如果你的游戏状态无论如何都会在原子中结束,那么你也可以考虑使用dotimes
来更新它。
(defn generate-game [world n-tribes]
(let [game (atom (create-game world))]
(dotimes [_ n-tribes] (swap! game (comp :game generate-tribe)))
game))
Iterate is also a fine solution. 迭代也是一个很好的解决方案。 More discussion at Iteratively apply function to its result without generating a seq . 在不产生seq的情况下,将函数迭代地应用于结果的更多讨论。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.