这是我的问题"递归反转Clojure中的序列"的后续内容.
是否可以使用Clojure"for"宏来反转序列?我试图更好地理解这个宏的局限性和用例.
这是我开始的代码:
((defn reverse-with-for [s]
(for [c s] c))
Run Code Online (Sandbox Code Playgroud)
可能?
如果是这样,我假设解决方案可能需要for
在定义可变var的某个表达式中包装宏,或者for宏的body-expr将以某种方式将序列传递给下一次迭代(类似于map
).
Clojure for
宏正在与任意Clojure序列一起使用.
这些序列可能会或可能不会像矢量那样暴露随机访问.因此,在一般情况下,您无法访问Clojure序列的最后一个元素而不会一直遍历它,这将使得以相反的顺序传递它是不可能的.
我假设你有类似的东西(类似Java的伪代码):
for(int i = n-1; i--; i<=0){
doSomething(array[i]);
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我们n
事先知道数组大小,我们可以通过索引访问元素.使用Clojure序列我们不知道.在Java中,使用数组和ArrayLists执行此操作是有意义的.然而,Clojure序列更像链接列表 - 您有一个元素,并且引用了下一个元素.
顺便说一下,即使有一种(可能是非惯用的)方法,它的时间复杂度也会像O(n ^ 2)那样,与链接帖子中更简单的解决方案相比,这是不值得的.列表的O(n ^ 2)和向量的O(n)要好得多(而且非常优雅和惯用.实际上,官方reverse
有实现).
编辑:
一般建议:不要尝试在Clojure中进行命令式编程,它不是为它而设计的.虽然很多事情看起来很奇怪或反直觉的(而不是从命令式编程众所周知的成语),一旦你习惯做的事情是很多的功能性的方式,我的意思是很多容易.
专门针对这个问题,尽管Java(和其他C-like)for
和Clojure for
同名的东西都不一样!首先是实际循环 - 它定义了流量控制.第二个是理解 - 从概念上看它是一个序列的更高函数和一个函数f要为它的每个元素完成,它返回另一个f(元素)序列.Java for
是一个声明,它不评估任何东西,Clojure for
(以及Clojure 中的任何其他东西)是一个表达式 - 它评估f(元素)的序列.
可能最简单的方法是使用序列函数库:http://clojure.org/sequences.另外,您可以在http://www.4clojure.com/上解决一些问题.第一个问题很容易,但随着你的进展,它们会越来越难.
*正如亚历山大的答案所示,问题的解决方案实际上是惯用的,非常聪明.为此感到荣幸!:)
以下是使用for来反转字符串的方法:
(defn reverse-with-for [s]
(apply str
(for [i (range (dec (count s)) -1 -1)]
(get s i))))
Run Code Online (Sandbox Code Playgroud)
请注意,此代码是无变异的.它与以下相同:
(defn reverse-with-map [s]
(apply str
(map (partial get s) (range (dec (count s)) -1 -1))))
Run Code Online (Sandbox Code Playgroud)
一个更简单的解决方案是:
(apply str (reverse s))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
672 次 |
最近记录: |