此代码基本上是循环遍历提供的字符串中的每个字母并继续直到z,然后递增前一个字母并在a处重新启动(例如从" bde"开始,接下来将是&#34 ; bdf",结束于" zzz" - 与典型循环的工作方式相同。)
我当然可以做一个嵌套的理解,因为这只是三个级别,但如果级别是任意深度的,我传统上接近的方式是使用递归(如下所示),基本上等于深度优先搜索。
这种方法的问题在于任何非平凡大小的输入都会使堆栈爆炸(例如," abcd"),我无法想到一个没有递归的好方法。在clojure代码下面实现的Python中的类似方法(具有一些小的差异,如累积结果在可变列表中)并没有达到输入的堆栈限制" abcd"。
我尝试使用loop / recur但是这个构造似乎不能在for macro中工作,因为调用必须在下一个循环迭代中挂起,因此不在尾部位置(至少我认为是原因)。
解决此类问题的最常用方法是什么?
;;; example using for macro
(defn gen-pw [pw r]
(cond (empty? pw) r
:else (flatten (for [x (range (int(first pw)) 123)]
(gen-pw (rest pw) (str r (char x)))))))
;;; example using map instead of for macro
(defn gen-pw [pw r]
(cond (empty? pw) r
:else (flatten (map #(gen-pw (rest pw) (str r (char %)))
(range (int(first pw)) 123)))))
(gen-pw "bde" "")
def gen_pw(pw,r='',final=[]):
if not pw:
final.append(r)
return
for letter in range(ord(pw[0]),123):
gen_pw(pw[1:],r + chr(letter))
return final
print(gen_pw('abcd'))
答案 0 :(得分:3)
您正在通过评估类似的内容生成一个非常过度嵌套的列表:
flatten
然后尝试用map
修复偶然的嵌套,当然这必须递归地走进你的巨大结构,然后爆炸。相反,生成一个平面列表开始。最简单的方法就是使用map
版本,将mapcat
替换为flatten
,然后删除现在不必要的(defn gen-pw [pw r]
(cond (empty? pw) [r]
:else (mapcat #(gen-pw (rest pw) (str r (char %)))
(range (int(first pw)) 123))))
:
r
您还需要将基本案例从[r]
调整为var io = require('socket.io').listen(server ....)
,就像我在此处所做的那样:您正在生成有效密码的列表,而不仅仅是一个密码,因此返回类型应始终为列表。
答案 1 :(得分:1)
执行此操作的一种方法是使用iterate
:
(defn transition [[text n]]
(let [c (nth text n)
nxt (if (= c \z) \z (-> c int inc char))
nxt-str (str (subs text 0 n) nxt (subs text (inc n) (dec (count text))))]
(if (= \z nxt)
[nxt-str (inc n)]
[nxt-str n])))
(defn ongoing? [[text n]]
(not (every? #(= \z %) text)))
(->> (iterate transition ["zza" 2])
(take-while ongoing?)
(map first))
请注意,对于["zza" 2]
,\a
位于第三位(因此为2),而对于[" dzs" 0] \d
位于第一位置(因此为0)。
答案 2 :(得分:1)
我将此问题声明视为关于计算笛卡尔积的问题,因此我倾向于仅推荐the lazy mutual-recursion implementation of that中的clojure.math.combinatorics。使用它就像:
(ns loops
(:require [clojure.math.combinatorics :refer [cartesian-product]]
[clojure.string :refer [join]]))
(defn chars-from [start]
(map char (range (int start) 123)))
(defn gen-pw [pw]
(map join (apply cartesian-product (map chars-from pw))))
(gen-pw "bde")
;;=> ("bde" "bdf" "bdg" ... "bee" "bef" "beg" ...
答案 3 :(得分:-1)
如果您达到了递归限制,请制作流程iterative rather than recursive。
你是对的,当递归过程调用是更大表达式的一部分(即不在尾部位置)时,它将产生递归过程。因此,请确保递归调用表示过程的整个值。
(defn gen-pw [pw r]
(let (s (successor pw))
(if (nil? s) ; (successor "zzz") is equal to nil
r
(gen-pw s (cons s r))))) ; (successor "bfe") is equal to "bff"