(defun insert (number lst)
(let ((before nil))
(if (= (length lst) 0) (return-from insert (list number)))
(loop for n from 0 to (1- (length lst)) do
(if (< number (nth n lst)) (progn (nconc before (list number)) (nconc before lst) (return-from insert before) )
(progn (nconc before (list (pop lst))))))
(nconc before (list number))
(return-from insert before)))
所以,我正在尝试插入一个在列表中排序的数字。原谅我的LISP练习不好,我不久前开始学习。
我将浏览列表并将元素插入“之前”列表中。如果我要插入的数字小于我当前所在的列表元素,我将数字附加到'之前'列表中,然后我将原始列表'lst'的左边附加到'之前'列表中,然后返回'之前'。
但是,此函数始终返回NIL。有什么想法吗?我的意思是,pop和nconc都具有破坏性......
答案 0 :(得分:4)
在Common Lisp中,在修改列表的意义上,在列表中插入值不是一个好习惯。相反,通常的做法是编写一个函数,给定一个列表,构建一个 new 列表,并在正确的位置插入元素。
例如,如果要在已排序的列表中插入数字,可以使用简单的递归函数来执行此操作:
(defun insert (number lst)
(cond ((null lst) (list number))
((<= number (car lst)) (cons number lst))
(t (cons (car lst) (insert number (cdr lst))))))
(insert 3 '(1 2 5 9))
(1 2 3 5 9)
在您的函数中,您使用nconc
,因为它不仅应修改列表,还应修改包含它的变量。但如果变量是空列表,则不会发生这种情况。例如:
> (setq a nil)
NIL
> (nconc a (list 4 5))
(4 5)
> a
NIL
您应始终将nconc
的结果分配给您要修改的变量,例如(setq a (nconc a (list 4 5)))
。
答案 1 :(得分:4)
让我们看一下代码中的一些问题。
效率低下:错误的数据结构或错误的操作选择
如果您在列表中使用LENGTH
或NTH
,则可以打赌这是错误的。列表是链接列表,LENGTH
和NTH
等操作可能很昂贵。特别是如果在循环或递归调用中完成了无数次。如果您想使用这些功能,那么向量是自然的选择。如果要使用列表,请尽量避免使用这些功能。链表的唯一“便宜”操作是列表的首位。
IF,RETURN
如果您需要RETURN
或RETURN-FROM
,那么您有可能不使用Lisp的内置数据流。
...
(if something (return ...))
...)
更好地写为
... (如果有的话 然后 别的)
<强> LOOP 强>
for n from 0 to (1- something)
只是
for n below something
<强> NCONC 强>
始终使用NCONC
的返回值。返回值是连接列表。
内置功能
CL-USER 12 > (defun insert (number list)
(merge 'list list (list number) #'<))
INSERT
CL-USER 13 > (insert 10 (list 1 2 3 7 8 10 40))
(1 2 3 7 8 10 10 40)