【问题标题】:Clisp : select sublists with a given lengthClisp :选择给定长度的子列表
【发布时间】:2018-06-27 22:26:41
【问题描述】:

在 Sublime Text 中使用 CLISP。

经验。在 CLISP 中:不到 1 年

我尝试解决这个练习已经有一段时间了......没有成功......正如你可能猜到的那样。

事实上,我必须创建一个函数来修改列表并只保留等于或大于给定数字的子列表(请看下面)

我必须工作的清单:

(setq liste '((a b) c (d) (e f) (e g x) f))

我应该找到这个结果:

(lenght 2 liste) => ((a b) (e f) (e g x))
liste => ((a b) (e f) (e g x))

这是我的代码:

(defun lenght(number liste)
    (cond
        ((atom liste) nil)
        ((listp (car liste))
            (rplacd liste (lenght number (cdr liste))) )
        ((<= (lenght number (car liste)) number)
         (I don't know what to write) )
        ((lenght number (cdr liste))) ) )

如果你能给我一些线索,让我找到好的结果,那就太好了。

谢谢各位。

【问题讨论】:

  • 这是作业吗?
  • 请注意,length 是一个标准的 lisp 函数 - 您可能想要使用明显拼写错误的 lenght 以外的其他东西。
  • 你不能改变像 '((a b) ...) 这样的文字。您确定它应该改变列表,而不仅仅是用结果创建一个新列表吗?如果您尝试以您的方式删除第一个元素,您将遇到各种问题。制作一个使用元素创建新列表的函数要容易得多。您正在混合您的函数 lenght 和标准函数 length,这是您应该用来检查元素长度的函数。
  • 是的,这是作业,我先向老师寻求帮助,他告诉我他不明白为什么我被阻止了...他说我应该再添加一个“测试”会好的。但是我还没有找到我应该做的测试......我把这个函数称为'lenght'(有一个错误,对此感到抱歉)因为我刚刚从法语翻译了这个练习。是的,我必须直接改变列表,以免浪费空间地址。这是我正在做的章节的目标。这是一种在法语中被称为“opération chirurgicale”(外科手术?)的方法。非常感谢

标签: common-lisp clisp


【解决方案1】:

修改列表没有多大意义,因为它会在列表的头部变得毛茸茸,以保留原始引用。返回一个新列表。

这是一个过滤操作。 Common Lisp 中的常用运算符是remove-if-not(或remove-if,或remove,取决于条件)。它需要一个谓词,该谓词应返回是否应保留元素。在这种情况下,它似乎是(lambda (element) (and (listp element) (&gt;= (length element) minlength)))

(defun filter-by-min-length (minlength list)
  (remove-if-not (lambda (element)
                   (and (listp element)
                        (>= (length element) minlength)))
                 list))

在许多情况下,当编译时条件已知时,loop 会生成更快的编译代码:

(defun filter-by-min-length (minlength list)
  (loop :for element :in list
        :when (and (listp element)
                   (>= (length element) minlength))
          :collect element))

这将返回一个满足条件的新列表。你可以这样称呼它(let ((minlength-list (filter-by-min-length 2 raw-list))) …)

许多基础课程一开始就坚持递归地使用cons cell上的原始操作来进行教学。

第一次尝试通常会忽略可能的堆栈耗尽。在每一步,你首先看看你是否在最后(然后返回 nil),是否应该丢弃第一个元素(然后返回对其余元素的递归结果),或者是否应该保留它(然后将其改为递归结果)。

如果尾调用优化可用,您可以将其重构为使用累加器。在每一步,不是先递归然后再consing,而是将保留的值cons到累加器上并将其传递给递归。最后,您不会返回 nil,而是将累加器反转并返回。

【讨论】:

  • 是的,这只是一个家庭作业,应该让我练习“外科手术”=改变指针相互作用的方式。老师不希望我使用:循环,if,lambda等。他只希望我使用:(defun A(b c)(cond((何时停止))((测试)执行)((测试)执行)((等))通过这种方式,我被阻止了,因为我没有找到问题,以便创建一个执行此操作的函数:1 - 仅选择子列表 = listp 2 - 计算元素的数量在子列表 3 中 - 检查它是否等于或大于给定的数字
  • 无论如何我今晚会尝试以某种方式应用您的建议并让您知道。谢谢你的回答=)
【解决方案2】:

嗯,我已经找到了我一直在寻找的答案,挠了挠头直到流血……

说真的,这是有效的解决方案(感谢您对长度的更正帮助我找到了解决方案^^):

(defun filter-by-min-length (min-length liste)
    (cond
        ((atom liste) nil)
        ((and (listp (car liste))(>= (length (car liste)) min-length))
            (rplacd liste (filter-by-min-length min-length (cdr liste))) )
        ((filter-by-min-length min-length (cdr liste))) ) )

【讨论】:

    【解决方案3】:

    非修改版本

    (defun filter-by-min-length (min-length le)
      (cond ((atom le) nil)
            ((and (listp (car le)) (>= (length (car le)) min-length))
             (cons (car le) (filter-by-min-length min-length (cdr le))))
            (t (filter-by-min-length min-length (cdr le)))))
    

    测试:

    (defparameter *liste* '((a b) c (d) (e f) (e g x) f))
    (filter-by-min-length 2 *liste*)
    ;; ((A B) (E F) (E G X))
    *liste*
    ;; ((A B) C (D) (E F) (E G X) F)  ; -> *liste* not modified
    

    为了养成良好的习惯,我建议使用defparameter 而不是setq,因为setq 的行为可能并不总是被定义(参见here)。链接里说:

    使用defvardefparameterlet 来引入新变量。使用setfsetq 改变现有变量。使用它们来引入新的 变量是未定义的行为

    【讨论】:

    • 感谢您的建议。我将在我未来的作品中应用它=)并且该链接非常有用。以后主要用defvar或者defparameter。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多