执行函数直到特定条件成立

发布于 2024-10-21 16:42:21 字数 392 浏览 2 评论 0原文

我想重复地将某个函数应用于某个状态,直到条件成立。

函数 f 接受一个状态,修改它并返回它。再次将 f 应用于返回的状态,依此类推。

我认为这会起作用。

(first (filter pred (iterate f x)))

但有点难看。另外,内存消耗并不理想,因为迭代器将被迫评估并保留中间状态,直到返回 pred 为 true 的状态,此时应该对中间状态进行垃圾收集。

我知道您可以编写一个简单的递归函数:

(loop [f x p] (if (p x) x (recur f (f x) p))

但我正在寻找一个核心库函数(或某些函数组合),它可以以相同的内存效率执行相同的操作。

I want to repeatedly apply some function to some state until a condition holds true.

Function f takes a state, modifies it and returns it. Apply f again to the returned state and so on.

I think this would work.

(first (filter pred (iterate f x)))

But it's a bit ugly. Plus memory consumption is not ideal since iterator would be forced to evaluate and keep intermediate states until the state on which pred holds true is returned, at which point intermediate states should be garbage collected.

I know you can write a simple recursive function:

(loop [f x p] (if (p x) x (recur f (f x) p))

But I'm looking for a core library function (or some combination of functions) that does the same thing with the same memory efficiency.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

九厘米的零° 2024-10-28 16:42:21

你真正想要的是 take-while

take-while
function

Usage: (take-while pred coll)
Returns a lazy sequence of successive items from coll while
(pred item) returns true. pred must be free of side-effects.

编辑

使用高阶函数来实现您想要的结果的一种方法可能是将您的函数包装到由 trampoline 使用的东西中,即返回最终结果或另一个函数的函数这将执行下一步。代码如下:

(defn iterable [f]            ; wraps your function
  (fn step [pred x]           ; returns a new function which will accept the predicate
    (let [y (f x)]            ; calculate the current step result
      (if (pred y)            ; recursion stop condition
        (fn [] (step pred y)) ; then: return a new fn for trampoline, operates on y
        y))))                 ; else: return a value to exit the trampoline

迭代执行如下:

(trampoline (iterable dec) pos? 10)

What you really want is take-while:

take-while
function

Usage: (take-while pred coll)
Returns a lazy sequence of successive items from coll while
(pred item) returns true. pred must be free of side-effects.

EDIT

A way to use higher order functions to achieve the result you want might be to wrap your function into something to be consumed by trampoline, namely a function that will either return the final result or another function which will execute the next step. Here's the code:

(defn iterable [f]            ; wraps your function
  (fn step [pred x]           ; returns a new function which will accept the predicate
    (let [y (f x)]            ; calculate the current step result
      (if (pred y)            ; recursion stop condition
        (fn [] (step pred y)) ; then: return a new fn for trampoline, operates on y
        y))))                 ; else: return a value to exit the trampoline

The iterative execution would go as follows:

(trampoline (iterable dec) pos? 10)
画中仙 2024-10-28 16:42:21

不确定您所说的迭代器是什么意思 - 您使用它就像它是迭代器一样,我只是想确定这就是您的意思。无论如何,你的解决方案对我来说看起来很好,而且一点也不难看。而且内存也不是问题:只要方便,iterate 就可以随意丢弃中间结果,因为您没有保留对它们的任何引用,只需在其中调用 filter 即可。 “流”方式。

Not sure what you mean by iterator - you're using it as if it were iterate, and I just want to be sure that's what you mean. At any rate, your solution looks fine to me and not at all ugly. And memory is not an issue either: iterate is free to throw away intermediate results whenever it's convenient because you aren't keeping any references to them, just calling filter on it in a "streaming" way.

绝不放开 2024-10-28 16:42:21

我认为你应该让你的循环成为一个简单的递归函数:

(defn do-until [f x p]
  (if (p x) x (recur f (f x) p)))

(do-until inc 0 #(> % 10)) ; => 11

I think you should just make your loop a simple recursive function:

(defn do-until [f x p]
  (if (p x) x (recur f (f x) p)))

(do-until inc 0 #(> % 10)) ; => 11
荭秂 2024-10-28 16:42:21

下降时怎么样

(first (drop-while (comp not pred) (iterate f x))

How about drop-while

(first (drop-while (comp not pred) (iterate f x))
权谋诡计 2024-10-28 16:42:21

我认为没有一个核心功能可以准确有效地完成此任务。因此,我将使用循环/递归来执行此操作,如下所示:

(loop [x initial-value]
  (if (pred x) x (recur (f x))))

循环/递归非常高效,因为它不需要额外的存储,并且在 JVM 中作为简单循环实现。

如果您要经常这样做,那么您始终可以将模式封装在宏中。

I don't think there is a core function that does this exactly and efficiently. Hence I would do this with loop/recur as follows:

(loop [x initial-value]
  (if (pred x) x (recur (f x))))

Loop/recur is very efficient since it requires no additional storage and is implemented as a simple loop in the JVM.

If you're going to do this a lot, then you can always encapsulate the pattern in a macro.

远昼 2024-10-28 16:42:21

听起来你想要 while 宏。

http://richhickey.github.com/clojure/clojure .core-api.html#clojure.core/while

用法:(测试和主体时)
当测试表达式为真时重复执行主体。假设
一些副作用会导致测试变为 false/nil。返回零

在稍微不同的用例中,for 宏也支持 :when 和 :while 选项。

http://richhickey.github.com/clojure/clojure .core-api.html#clojure.core/for

用法:(对于 seq-exprs body-expr)
列表理解。取一个或多个向量
绑定形式/集合表达式对,每个对后跟零个或多个
修饰符,并产生 expr 的惰性求值序列。
集合以嵌套方式迭代,最右边最快,
嵌套的 coll-exprs 可以引用之前创建的绑定
绑定形式。支持的修饰符有: :let [binding-form expr ...],
:测试时,:测试时。

(取 100(对于 [x(范围 100000000)y(范围 1000000):while (< yx)] [xy]))

Sounds like you want the while macro.

http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/while

Usage: (while test & body)
Repeatedly executes body while test expression is true. Presumes
some side-effect will cause test to become false/nil. Returns nil

In a slightly different use case the for macro supports :when and :while options too.

http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/for

Usage: (for seq-exprs body-expr)
List comprehension. Takes a vector of one or more
binding-form/collection-expr pairs, each followed by zero or more
modifiers, and yields a lazy sequence of evaluations of expr.
Collections are iterated in a nested fashion, rightmost fastest,
and nested coll-exprs can refer to bindings created in prior
binding-forms. Supported modifiers are: :let [binding-form expr ...],
:while test, :when test.

(take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文