【问题标题】:Removing last two elements from a list in Lisp从 Lisp 列表中删除最后两个元素
【发布时间】:2017-07-21 05:27:02
【问题描述】:

我需要从公共列表中的列表中删除最后两个元素,但我只能删除一个。有什么办法?

(defun my-butlast (list)
        (loop for l on list
              while (rest l)
              collect (first l)))

【问题讨论】:

  • while (rest (rest l))?
  • @melpomene 我正在尝试不同的方法来实现它
  • (remove-if #'atom '(1 2 3 (1 2 3 4) 5) :count 2 :from-end t) => (1 2 (1 2 3 4)).
  • @jkiiski 您能否将它集成到 a 函数中。plz MyList = ( A B C D)..我正在尝试编写一个函数以从列表中删除 C D。使其变为 Mylist = (A B)
  • (subseq list :start 0 :end (- (length list) 2)) - 这将是我的 goto 解决方案

标签: common-lisp


【解决方案1】:

简单:reverse、pop、pop、reverse ;-) 1

更有效的是,以下方法也有效:

(let ((list '(a b c d)))
  (loop 
    for x in list
    for y in (cddr list)
    collect x))

这也可以写成任意L和N:

(mapcar #'values L (nthcdr N L)) 

之所以有效,是因为对多个列表的迭代受到最短列表的限制。这里重要的是第二个列表的长度(我们不关心它的值),它是原始列表的长度减去 N,当该值为正时,否则为零。请注意,NTHCDR 可以方便地使用大于参数中给出的列表长度的大小。在第二个例子中,我使用VALUES 函数作为广义恒等函数; MAPCAR 仅使用计算值的主值,因此可以按需要工作。 该行为与实际的 BUTLAST2 函数一致,该函数在 N 大于列表中的元素数时返回 nil。实际的BUTLAST函数也可以处理不正确的(点)列表,但上面的版本不能。


1. (alexandria:compose #'nreverse #'cddr #'reverse)

2. BUTLAST 被指定为等同于(ldiff list (last list n))。我完全忘记了LDIFF的存在!

【讨论】:

  • 在这种情况下也可以忍受痛苦cddr。这是如何编写的,尽管您可以将其设为通用函数,将购物金额作为参数。
  • @Sylwester 是的,在示例中使用 CDDR 并在之后进行概括更有意义。谢谢。
  • 不需要这个。 butlast 存在于标准中,并采用可选的第二个参数指定要排除多少元素。我添加了an answer
【解决方案2】:

标准中有一个函数:butlast,或者如果你愿意修改输入列表,nbutlast

butlast 返回 list 的副本,其中最后 n 个 conses 已被省略。如果未提供 n,则其值为 1。如果列表中的 conses 少于 n,则返回 nil,对于 nbutlast,不修改列表。

nbutlast 类似于 butlast,但 nbutlast 可以修改列表。它将 cons n+1 的 cdr 从列表的末尾更改为 nil。

例子:

CL-USER> (butlast '(1 2 3 4 5) 2)
(1 2 3)
CL-USER> (nbutlast (list 6 7 8 9 10) 2)
(6 7 8)

你调用你的函数 my-butlast 的事实表明你可能知道这个函数,但你没有提到不想使用这个函数,所以我认为它仍然是公平的游戏。总结起来很简单:

CL-USER> (defun my-butlast (list)
           (butlast list 2))
MY-BUTLAST
CL-USER> (my-butlast (list 1 2 3 4))
(1 2)

【讨论】: