[英]Build list in Lisp using an iterative recursive function
Super newbie in Lisp but at least I am trying so forgive me if the approach seems a bit strange. Lisp 的超级新手,但至少我正在努力,如果这种方法看起来有点奇怪,请原谅我。
I am open to learn new ideas but I will definitely need to learn whats wrong with my approach.我愿意学习新想法,但我肯定需要了解我的方法有什么问题。
I have a function that builds a list using an iterative recursive approach.我有一个使用迭代递归方法构建列表的函数。
(defun create-tree-iteratively(sub-list)
(if (equal (length sub-list) 1)
sub-list
(loop for i in sub-list
do(setq subtree (list i))
do(setq sub-sub-list (remove i sub-list))
do(append subtree (create-tree-iteratively sub-sub-list))
)
)
)
Input to my program is我的程序的输入是
'(1 2 3)
Expected output is预期输出是
'((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
My loops (recursion) runs file.我的循环(递归)运行文件。 I have issues in combing the output of recursion appropriately.我在适当地组合递归输出时遇到问题。
It is preferable to not have closing parentheses on their own lines, the usual convention in Lisp is to have parentheses grouped at the end, like so: )))
.最好不要在自己的行上使用右括号,Lisp 中通常的约定是将括号放在最后,如下所示:) )))
。
Since cons-cells have only two slots, CAR
and CDR
, when they are used as a list they do not hold the length of the list.由于 cons-cells 只有两个时隙, CAR
和CDR
,当它们用作列表时,它们不保存列表的长度。 So the only way to compute the length is to traverse the whole chain of cells, which is exactly what your function is already doing.所以计算长度的唯一方法是遍历整个单元链,这正是你的函数已经在做的。 If your list is of size N, you'll have to compute the length N times, which makes the number of steps in your function proportional to N*N.如果列表的大小为 N,则必须计算长度 N 次,这使得函数中的步数与 N*N 成正比。
In a loop, a single DO can be followed by multiple expressions, you do not need to repeat the DO keyword.在一个循环中,一个 DO 后面可以跟多个表达式,不需要重复 DO 关键字。 Also, add spaces before opening parentheses.另外,在开括号之前添加空格。
SETQ is not supposed to be applied with unbound variables, like subtree
or sub-sub-list
. SETQ 不应应用于未绑定的变量,例如subtree
或sub-sub-list
。 You should first have a surrounding let
where you introduce local variables (eg around the loop
), or use with
clauses in your loop.你应该首先有一个周围的let
引入局部变量(例如围绕loop
),或者在你的循环中使用with
子句。 Or better, use the existing facilities of LOOP to avoid doing the mutation yourself.或者更好的是,使用 LOOP 的现有设施来避免自己进行变异。
The return value of APPEND
is important, since it 's the results of appending the arguments (which are left unmodified). APPEND
的返回值很重要,因为它是附加参数(未修改)的结果。 But here you do not use the return value, which makes the whole expression useless.但是这里你没有使用返回值,这使得整个表达式毫无用处。
Instead of computing the length, it is sufficient to check whether the input lists is empty, contains one elements or more (without counting).无需计算长度,只需检查输入列表是否为空、是否包含一个或多个元素(不计算)就足够了。 Also, you can use collect
to collect all trees as a list.此外,您可以使用collect
将所有树收集为列表。 I am not sure the result for a singleton input list is correct, maybe it should be (list list)
.我不确定单例输入列表的结果是否正确,也许应该是(list list)
。
(defun create-tree (list)
(if (null (rest list))
;; covers both empty list and list with a single element
list
;; otherwise, collect a list of trees
(loop
for i in list
;; collect all trees rooted at i, where a tree is a list (r c1 .. cn)
;; with R the root node and C1...CN each child tree. The child trees
;; are build recursively, with i removed from the list of values.
collect (list* i (create-tree (remove i list))))))
Some initial notes.一些初步的笔记。
setq
you create it by some binding form such as let
;您不会通过setq
在函数中创建新绑定,而是通过某种绑定形式(例如let
创建它;append
, you create a new list which has the new things added to it, and since lists are linked lists and not variable-length arrays in drag, append
takes time proportional to the length of the list.您不会通过append
在列表末尾添加新内容,而是创建一个新列表,其中添加了新内容,并且由于列表是链接列表而不是拖动中的可变长度数组,因此append
花费的时间与列表的长度。That being said, here are three versions of what I think you want: the first implements what I'd think of as a consistent algorithm, the second implements what I think you may want, and the final one abstracts out the termination test & can do either (or anything else)).话虽如此,这里有我认为你想要的三个版本:第一个实现我认为的一致算法,第二个实现我认为你可能想要的,最后一个抽象出终止测试 & 可以做任何一个(或其他任何事情))。
(defun make-permuted-tree (l)
;; this builds the tree all the way down
(if (null l)
'()
(loop for e in l
collect (cons e (make-permuted-tree (remove e l))))))
(defun make-permuted-tree/strange (l)
;; this stops before the end
(if (null (rest l))
l
(loop for e in l
collect (cons e (make-permuted-tree/strange (remove e l))))))
(defun make-permuted-tree/general (l &key (base-test (lambda (b)
(null b))))
;; this stops where you want it to, which by default is at the end
(labels ((make-permuted-tree (lt)
(if (funcall base-test lt)
lt
(loop for e in lt
collect (cons e (make-permuted-tree (remove e lt)))))))
(make-permuted-tree l)))
As examples of these:作为这些例子:
> (make-permuted-tree/strange '(1 2 3))
((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
> (make-permuted-tree '(1 2 3))
((1 (2 (3)) (3 (2))) (2 (1 (3)) (3 (1))) (3 (1 (2)) (2 (1))))
> (make-permuted-tree/general '(1 2 3))
((1 (2 (3)) (3 (2))) (2 (1 (3)) (3 (1))) (3 (1 (2)) (2 (1))))
> (make-permuted-tree/general '(1 2 3) :base-test (lambda (b)
(null (rest b))))
((1 (2 3) (3 2)) (2 (1 3) (3 1)) (3 (1 2) (2 1)))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.