从列表中删除列表

时间:2013-10-21 19:36:02

标签: lisp common-lisp

我正在编写一个需要从列表中删除某个元素的简单函数。该列表里面有3个列表,我想在第二个列表中搜索给定的值。第二个列表的元素也是列表(id x y)。

我的函数接收listid作为参数,并且必须从具有该id的第二个列表中删除该元素。

(defun rem (list id)
  (dolist (var (nth 1 list))
    (cond (equal id (nth 0 var))
          (delete var (nth 1 list))))
)

我搜索给定列表的第二个列表,当我找到带有id的元素时,我将其删除。问题是我总是得到NIL。我也尝试使用函数remove,但结果是一样的。

1 个答案:

答案 0 :(得分:3)

此代码存在许多问题,并且描述它们实际上比构建工作示例更长,因此我将首先显示工作版本,然后浏览您提供的代码。请仔细阅读第二部分,并确保您了解原始代码中的问题。

工作版

根据您的说明,您希望删除 第一个元素为list第二个元素的每个元素{1}}。我不确定你想要返回的是什么,但假设它像id,但是使用新的第二个元素,你可以做类似下面的事情。我强调该段中的某些词语,因为它们对解决这个问题很重要。您有一个list,并且您希望从具有id的序列中删除内容。您可以通过调用idremove(或delete)执行此操作,其中(remove id sequence :key <key>)是一个从序列元素中提取值以与{{1}进行比较的函数}。您要从keyid的{​​{1}}中删除这些元素。你会用

(second list)

这样做。在上下文中,您将获得如下函数:

first

以下是一个例子:

id

您的代码问题

有一些问题:

  1. 您不应尝试定义名为(remove id (second list) :key 'first) 的函数。
  2. 您的代码中存在语法错误。
  3. (defun bex-remove (list id) (list (first list) (remove id (second list) :key 'first) (third list))) 不一定会产生您的代码预设的副作用。
  4. 默认情况下,
  5. (bex-remove '((1 2 3 4) ; values don't matter ((id-a x1 y1) (id-b x2 y2) (id-a x3 y3) (id-b x4 y4)) (5 6 7 8)) ; values don't matter 'id-a) ;=> ((1 2 3 4) ((ID-B X2 Y2) (ID-B X4 Y4)) (5 6 7 8)) 会返回rem
  6. 更详细:

    Common Lisp包中已经有一个名为REM的函数来计算余数。试图在SBCL中评估您的定义发出错误信号:

    delete

    你在CLISP中遇到类似的错误(你用它来标记问题,所以我认为它是你正在使用的实现):

    dolist

    我们会重命名您的函数nil,以便我们可以继续,我们会看到会发生什么。当尝试在SBCL中编译调整后的定义时,我们会收到有关未定义变量Lock on package COMMON-LISP violated when setting fdefinition of REM while in package COMMON-LISP-USER. [Condition of type SYMBOL-PACKAGE-LOCKED-ERROR] See also: SBCL Manual, Package Locks [:node] Common Lisp Hyperspec, 11.1.2.1.2 [:section] [1]> (defun rem (x) x) ; not the same as your definition, but still a function named rem ** - Continuable Error DEFUN/DEFMACRO(REM): #<PACKAGE COMMON-LISP> is locked If you continue (by typing 'continue'): Ignore the lock and proceed The following restarts are also available: ABORT :R1 Abort main loop 的警告。

    %rem

    在CLISP中,您必须在收到类似警告之前进行编译:

    delete

    cond的语法是equal,这意味着每个测试及其关联的表达式都需要用括号括起来。更新以解决此问题,我们现在有:

    ; --> IF COND 
    ; ==>
    ;   (IF DELETE
    ;       (PROGN VAR (NTH 1 LIST))
    ;       NIL)
    ; 
    ; caught WARNING:
    ;   undefined variable: DELETE
    
    ; ==>
    ;   (IF EQUAL
    ;       (PROGN ID (NTH 0 VAR))
    ;       (COND (DELETE VAR (NTH 1 LIST))))
    ; 
    ; caught WARNING:
    ;   undefined variable: EQUAL
    ; 
    ; compilation unit finished
    ;   Undefined variables:
    ;     DELETE EQUAL
    ;   caught 2 WARNING conditions
    

    当我们编译它时,我们仍然在SBCL中收到一些警告,但是即使在编译期间CLISP也不会生成类似的警告:

    CL-USER> (defun %rem (list id)
               (dolist (var (nth 1 list))
                 (cond (equal id (nth 0 var))
                       (delete var (nth 1 list))))
               )
    %REM
    CL-USER> (compile '%rem)
    WARNING: in %REM : EQUAL is neither declared nor bound,
             it will be treated as if it were declared SPECIAL.
    WARNING: in %REM : DELETE is neither declared nor bound,
             it will be treated as if it were declared SPECIAL.
    %REM
    2
    2
    

    这告诉我们,您确实需要保存 (cond (test expr*)*)的结果。 (defun %rem (list id) (dolist (var (nth 1 list)) (cond ((equal id (nth 0 var)) (delete var (nth 1 list)))))) 可以以任意方式修改列表,但根本不需要修改任何内容。例如,在以下代码中,虽然; in: DEFUN %REM ; (DELETE VAR (NTH 1 LIST)) ; ; caught STYLE-WARNING: ; The return value of DELETE should not be discarded. ; ; caught STYLE-WARNING: ; The return value of DELETE should not be discarded. ; ; compilation unit finished ; caught 2 STYLE-WARNING conditions 返回列表delete,但未修改变量delete的值。

    x

    所以你可能想写的是:

    (delete 1 x)

    这段代码不太可能有用。一,你在迭代它时修改(2 3),这不太可能有好结果。我不确定代码应该做什么。由于您正在迭代CL-USER> (let ((x (list 1 2 3))) (delete 1 x) ; could return, e.g, (cdr x) x) ;=> (1 2 3) (defun %rem (list id) (dolist (var (nth 1 list)) (cond ; or (when (equal id (nth 0 var)) ((equal id (nth 0 var)) ; (setf (nth 1 list) ...)) (setf (nth 1 list) (delete var (nth 1 list))))))) 必须具有

    形式
    (nth 1 list)

    并且由于您选择了(nth 1 list),因此每个list也必须是一个列表,因此列表的格式为

    (<first-element> (var1 var2 ...) ...)
    

    无论如何,您的(nth 0 var)仍会返回varidolist的语法是

    (<first-element> ((<elt10> ...) (<elt20> ...) ...) ...)
    

    ,可选的dolist默认为nil。我不确定你想要归还什么,但也许它是列表,在这种情况下你会做什么

    dolist (var list-form [result-form]) declaration* {tag | statement}*
    

    例如:

    result-form