我从长度为n的列表中计算出n个组合中的k.我发现python代码非常简洁,所以我做了直接翻译.
def comb(sofar, rest, n):
if n == 0:
print sofar
else:
for i in range(len(rest)):
comb(sofar + rest[i], rest[i+1:], n-1)
comb("", "abcde", 3)
Run Code Online (Sandbox Code Playgroud)
产量:abc,abd,abe等......
将被翻译为clojure代码:
(defn comb [sofar v n]
(if (= n 0)
(print sofar)
(for [i (range 0 (count v))]
(comb (str sofar (nth v i)) ;don't it need to be recur ?
(subvec v (inc i))
(dec i)))))
Run Code Online (Sandbox Code Playgroud)
嵌套循环/递归非常混乱.
问题是如何更改代码以执行与python代码相同的功能?
我的clojure代码似乎没有做同样的工作.
首先,如果你想要一个clojure解决方案,请考虑使用clojure术语,将函数写入生成惰性序列结果的序列,并让最终使用者在需要时将这些函数减少为字符串.在下面,我根本不使用打印,只返回延迟序列,让repl成为打印机.
此外,你试图将一个python for直接翻译成一个clojure for来做循环,这不是它的用途(没有双关语意).clojurefor是一个序列生成器,所以你可能会在那里感到困惑.
要获得问题的简单解决方案,您可以使用math.combinatorics:
user=> (require '[clojure.math.combinatorics :as m])
user=> (m/combinations "abcde" 3)
((\a \b \c) (\a \b \d) (\a \b \e) (\a \c \d) (\a \c \e) (\a \d \e) (\b \c \d) (\b \c \e) (\b \d \e) (\c \d \e))
Run Code Online (Sandbox Code Playgroud)
然后,如果需要,您可以编写一个映射以将其转换为与python相同的输出的字符串.
user=> (map #(apply str %1) (m/combinations "abcde" 3))
("abc" "abd" "abe" "acd" "ace" "ade" "bcd" "bce" "bde" "cde")
Run Code Online (Sandbox Code Playgroud)
但是,我怀疑你正在寻找更多关于循环的教程.
这里有另一个解决这个问题的方法,用于创建一个函数来将序列作为字符返回,它产生与上面例子相同的序列,并且也可以包含在字符串输出的映射中.它使用带有cond块的递归来控制迭代的结束.
这是另一篇关于做同样组合的好文章,解释了它如何通过将问题解构为本质上递归的问题来进行递归.
如果您想了解有关复发与强制循环的更多信息,请查看此SO问题.
而且这里有一个要点与循环的一些例子/复发VS递归阶乘这样你就可以直接看到两者之间的语法风格.
在习惯于编写生成这样的序列的函数方面,我发现Little Schemer是解释思考过程的优秀资源.它是用方案编写的,但很容易理解并适用于clojure.在此之后,您可以查看更高阶函数(map/reduce)而不是使用循环.
总而言之,当你这样做时,如果你在任何地方使用惰性函数,你的结果通常是懒惰的,并且你想尝试使用尾递归,如果你进行递归,这样你在使用大组合时就不会打击堆栈,并转储您不感兴趣的值.