将项目替换为列表中的每个匹配项

Substituting item to every occurance in a list

我刚刚开始学习 Lisp。我的问题是每次出现在列表中时我都试图替换它。我必须使用递归并且没有任何循环来做到这一点。该函数以 (subste x y L).

开头

示例为:

(subste 7 t '(it is 7)) → (IT IS T)
(subste 7 nil '(7 is not to (7))) → (NIL IS not TO (NIL))
(subste 7 nil '(5 is not (22))) → (5 is not (22))

这是我目前所要做的:

(defun subste (x y L)
  (cond ((null L) nil)
        ((not (= (car L) x))
         subste (x y (cdr L)))
        ((= (car L) x)
         (let L 'y))))

我已经 运行 多次并对其进行了多次调整,但考虑到错误消息提供的信息很少并且才刚刚开始学习 Lisp,所以运气不佳。谢谢

SUBST 已经实现了您想要的行为。您似乎只是希望新旧元素的顺序不同,所以一个简单的包装器就可以:

(defun subste (x y l)
  (subst y x l))

如果您想自己实现,下面是一个简单的版本。注意不同的分支:

  • 递归树总是涉及对树的第一个元素进行递归调用,对树的其余部分进行另一个元素。
  • Return nil 在树的尽头。
  • 如果我们找到要替换的元素,我们会更改它。
  • 对于任何其他原子,我们不需要递归,我们只是 return 原子。

这里是例子:

(defun subste (x y l)
  (cond ((null l) nil)
        ((eql l x) y)
        ((atom l) l)
        (T (cons (subste x y (first l))
                 (subste x y (rest l))))))

此版本不完整:您无法替换非 eql 元素(如字符串或子列表)。如果需要,您可以添加一个测试函数作为参数,而不是始终使用 EQL

写一个subst的实现只是遍历树,检查树中的节点是否与old相同,并将它们替换为 new。在 Common Lisp 中,像这样的函数通常采用 test 函数来确定如何比较元素(通常是 key 函数,但我已经此处省略)。这导致了这样的事情:

(defun my-subst (old new tree &key (test 'eql))
  "Returns a completely fresh tree like TREE, but with occurrences of
OLD replaced by NEW.  The resulting tree shares no structure with the 
original TREE, except for leaves."
  (cond
    ;; If the current tree is the OLD element,
    ;; return the NEW element instead.
    ((funcall test old tree) new)
    ;; If the current tree is a cons cell,
    ;; call MY-SUBST recursively on both
    ;; the CAR and CDR of the tree, and
    ;; then CONS the results back together.
    ((consp tree) (cons (my-subst old new (car tree) :test test)
                        (my-subst old new (cdr tree) :test test)))
    ;; Otherwise, just return TREE.
    (t tree)))
(my-subst 'x 42 '(1 x 2 (3 x (4 (x) 5))))
;=> (1 42 2 (3 42 (4 (42) 5)))

现在,由该实现创建的 return 树总是全新的。也就是说,即使 old 元素 never 出现在树中,您仍然会得到一棵全新的树。根据您的用例,这可能有点浪费内存。 检查 递归调用的结果是否与其输入相同可能是有益的。在这种情况下,您可以 return 输入:

(defun my-subst (old new tree &key (test 'eql))
  "Returns a tree like TREE, but with occurrences of OLD
replaced by NEW.  The resulting tree may share structure
with TREE."
  (cond
    ((funcall test old tree) new)
    ((consp tree)
     (let ((new-car (my-subst old new (car tree) :test test))
           (new-cdr (my-subst old new (cdr tree) :test test)))
       (if (and (eq (car tree) new-car)
                (eq (cdr tree) new-cdr))
           tree
           (cons new-car new-cdr))))
    (t tree)))
(let* ((t1 '(1 x 2 (3 x (4 (x) 5))))
       (t2 (my-subst 'x 42 t1))
       (t3 (my-subst 'y 84 t1)))
  (list (eq t1 t2)
        (eq t1 t3)))

;=> (NIL T) ; t1 != t2, but t1 == t3

您想要哪种取决于具体情况,但最好能够两者都做到。