我想使用mapcar / lambdas来解决这个问题。我知道如何经常这样做。到目前为止,我有类似的东西:
(defun removal (lista elem &optional final)
(cond
((and (atom lista) (eql lista elem)) nil)
((listp lista) (mapcan (lambda (e) ( removal e elem final)) lista))
(t (nconc final lista))))
出于某种原因,它到目前为止还没有运行,但这是一个草案。任何想法放置mapcar或如何摆脱可选列表最终的想法?我需要使用map函数或lambdas和递归来解决这个问题。
即使添加了lambda和mapcan之后仍然无法正常工作,它根本无法构建列表
答案 0 :(得分:2)
一些评论:
当您处理多个级别的列表时,您通常使用树,不是吗?我会将removal
和lista
替换为tree-remove
和tree
。
如果lista
是原子而不是数字怎么办?在使用lista
之前,您最好先检查=
是否为数字,或者接受:test
参数。
你说由于某种原因,它甚至没有运行。你没有错误信息吗?它说什么? 未定义函数:lista 的东西?您在正常评估上下文中的列表的第一个位置使用lista
符号。
为避免使用可选参数,请使用labels
定义本地函数。这是另一个演示如何使用标签的示例:
(defun tree-occurences (tree number)
(let ((counter 0))
(labels ((count-occurences (form)
(typecase form
(sequence (map nil #'count-occurences form))
(number (when (= form number) (incf counter))))))
(count-occurences tree))
counter))
答案 1 :(得分:2)
由于不清楚你有什么样的约束,这里有两个解决方案,第一个是递归的,没有高阶函数,第二个是更高阶函数。
(defun remove-from-tree(el tree)
(cond ((null tree) nil)
((consp (car tree))
(cons (remove-from-tree el (car tree))
(remove-from-tree el (cdr tree))))
((eql (car tree) el) (remove-from-tree el (cdr tree)))
(t (cons (car tree) (remove-from-tree el (cdr tree))))))
在此解决方案中,cond
中有四种可能的情况:
eql
,那么忽略汽车并继续递归地将函数应用到cdr,这是第二个版本:
(defun remove-from-tree(el tree)
(mapcan (lambda(subtree)
(cond ((null subtree) (list nil))
((consp subtree) (list (remove-from-tree el subtree)))
((eql subtree el) nil)
(t (list subtree))))
tree))
在这种情况下,使用了功能mapcan
,并且由于此nconc
所有结果,我们必须将list
添加到内部函数的cond
的几个分支中
应用于树的“顶部”元素的内部函数有四种情况:
(list nil)
,以便mapcan
可以将此结果与其他结果连接,nil
(这不会出现在mapcan
的结果中),答案 2 :(得分:2)
您提到使用 mapcar 和 lambda ,但Common Lisp还包含mapcan,这可能会更有用。 mapcan 函数类似于mapcar,但它不是创建函数结果列表,而是获取函数结果并将它们连接成一个列表。例如,
(mapcan (lambda (x)
(list x x))
'(1 2 3))
;=> (1 1 2 2 3 3)
这对于过滤类型任务很方便,因为您可以让您在列表上进行映射的功能始终返回一个列表,如果它返回 nil ,那么您可以使用该功能。基本上过滤掉了那个元素。 E.g:
(mapcan (lambda (x)
(if (evenp x)
(list x) ; if even, return (x)
'())) ; if odd, return ()
'(1 2 3 4 5 6))
;;=> (2 4 6)
因此,您可以使用类似的东西从树的所有级别删除元素。内部%remove-all 功能可以完成实际工作,但始终会返回一个列表,即使原始输入不是列表。所以,我们只需要从中提取第一个元素。
(defun remove-all (element tree &key (test #'eql))
(labels ((%remove-all (element tree)
(cond
((funcall test element tree) '())
((atom tree) (list tree))
(t (list (mapcan (lambda (child)
(%remove-all element child))
tree))))))
(car (%remove-all element tree))))
(remove-all 3 '(1 2 3 (3 2 1 (1 3 2))))
;;=> (1 2 (2 1 (1 2)))
(remove-all 3 5)
;;=> 5
(remove-all 3 3)
;;=> NIL
(remove-all 3 '(3))
;;=> NIL