从列表中删除列表 [英] Remove list from list

查看:62
本文介绍了从列表中删除列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a simple function that needs to remove a certain element from a list. The list has 3 lists inside, and I want to search the 2nd one for a given value. This 2nd list's elements are also lists (id x y).

我的函数接收一个 list 和一个 id 作为参数,并且它必须从具有该ID的第二个列表中删除该元素.

My function receives a list and and id as arguments, and it has to remove the element from the second list that has that id.

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

我搜索给定列表的第二个列表,当我找到具有 id 的元素时,将其删除.问题是我总是得到 NIL .我也尝试过使用功能 remove ,但是结果是相同的.

I search the second list of the given list, and when I find the element with id, I delete it. The problem is that I'm always getting NIL. I tried with function remove as well, but the result is the same.

推荐答案

此代码存在许多问题,描述它们实际上比构造一个有效的示例要长,因此我将首先展示一个有效的版本,然后然后遍历您提供的代码.不过,请通读第二部分,并确保您了解原始代码中的问题.

There are a number of issues with this code, and describing them is actually longer than constructing a working example, so I'll show a working version first, and then walk through the code that you provided. Please read through that second section and be sure you understand the issues in the original code, though.

根据您的描述,您要删除 第一 列表 second 元素的每个元素元素是 id .我不确定要返回的是什么,但是假设它类似于 list ,但是有了第二个新元素,您可以执行以下操作.我在该段中强调了某些词,因为它们对于解决这个问题很重要.您有一个 id ,并且想要从具有该 id 的序列中删除内容.您可以使用 删除 (或通过调用(删除ID序列:key< key>) delete ),其中 key 是一个从序列元素中提取值的函数与 id 进行比较.您想从 first id (第二个列表)中删除这些元素.您将使用

Based on your description, you want to remove each element of the second element of list whose first element is id. I'm not sure exactly what it is that you want to return, but assuming that it's like list, but with the new second element, you can do something like the following. I emphasized certain words in that paragraph, because they're important for solving this problem. You have an id, and you want to remove things from a sequence that have that id. You can do that with remove (or delete) by calling (remove id sequence :key <key>), where key is a function that extracts a value from the sequence elements to compare against id. You want to remove those elements from (second list) whose first is id. You'd use

(remove id (second list) :key 'first)

做到这一点.在上下文中,您将获得如下功能:

to do that. In context, you'd get a function like this:

(defun bex-remove (list id)
  (list (first list)
        (remove id (second list) :key 'first)
        (third list)))

这是一个例子:

(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))

与您的代码一起发出

有几个问题:

  1. 您不应尝试定义名为 rem 的函数.
  2. 您的代码中有语法错误.
  3. 删除不一定具有您的代码所假定的副作用.
  4. 默认情况下,
  5. dolist 返回 nil .
  1. You shouldn't try to define a function named rem.
  2. You've got syntax errors in your code.
  3. delete doesn't necessarily have the side effects that your code presupposes that it does.
  4. dolist, by default, returns nil.

详细信息:

已经有一个名为 REM 在计算余数的Common Lisp软件包中.尝试在SBCL中评估您的定义会提示错误:

There's already a function named REM in the Common Lisp package that computes a remainder. Trying to evaluate your definition in SBCL signals an error:

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]

您在CLISP中也遇到了类似的错误(已将其标记为问题,因此我认为这是您正在使用的实现):

You get a similar error in CLISP (with which you've tagged the question, so I assume it's the implementation that you're using):

[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 ,以便我们继续操作,然后看看会发生什么.尝试在SBCL中编译调整后的定义时,我们会收到有关未定义变量 delete equal 的警告.

We'll rename your function %rem so that we can continue, and we'll see what happens. When try compile the adjusted definition in SBCL, we get a warnings about undefined variables delete and 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

在CLISP中,您必须先进行编译,然后才能收到类似的警告:

In CLISP you'll have to compile before you get similar warnings:

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 的语法为(cond(test expr *)*),这意味着每个测试及其相关表达式都需要用括号括起来.已更新以解决此问题,我们现在有:

The syntax of cond is (cond (test expr*)*), which means that each test and its associated expressions need to be wrapped in parentheses. Updated to fix that, we now have:

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

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

When we compile that, we still get some warnings in SBCL, but CLISP doesn't generate similar warnings, even during compilation:

; 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 可以以任意方式修改列表,但根本不需要修改任何内容.例如,在以下代码中,尽管(delete 1 x) 确实返回了一个列表,但变量 x 的值并未被修改.(2 3).

What this is telling us is that you really need to save the results from delete. delete can modify a list in arbitrary ways, and yet isn't required to modify anything at all. For instance, in the following code, the value of the variable x isn't modified, although (delete 1 x) does return a list (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)))))))

此代码不太可能做很多有用的事情.第一,您正在迭代(第n个1个列表),这不太可能取得良好的效果.我不确定代码应该做什么.由于您要遍历(第n个列表),因此 list 的格式必须为

This code isn't likely to do much that's useful. One, you're modifying (nth 1 list) while you're iterating over it, which is unlikely to have good results. I'm not sure what the code is supposed to do, exactly. Since you're iterating over (nth 1 list), list must have the form

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

并且由于您采用(nth 0 var),因此每个 vari 也必须是一个列表,因此list的格式为

and since you take (nth 0 var), then each vari must also be a list, so list has the form

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

无论如何,您的 dolist 仍将返回 nil . dolist 的语法是

Regardless, your dolist will still return nil. The syntax for dolist is

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

,并且该可选的 result-form 默认为 nil .我不确定您要返回的确切内容,但也许是列表,在这种情况下,您会这样做

and that optional result-form defaults to nil. I'm not sure exactly what you want to return, but maybe it's list, in which case you'd do

(dolist (var list list)
  …)

例如:

(let ((list (list 1 2 3)))
  (dolist (x list)                ; return default (nil)
    (+ x x)))
;=> NIL

(let ((list (list 1 2 3)))
  (dolist (x list (reverse list)) ; return something
    (+ x x)))
;=> (3 2 1)

这篇关于从列表中删除列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆