【问题标题】:Common Lisp function to determine lengths of nested lists in a list用于确定列表中嵌套列表长度的 Common Lisp 函数
【发布时间】:2020-03-28 08:06:59
【问题描述】:

我只被允许使用do 构造,我仍然无法理解这个概念。我尝试了以下代码,但它返回nil

(defun fun(list)
(do ((i 0 (+ i 1)) (l '() (if (listp (nth i list)) (append l (list (length (nth i list)))))))
((null (nth i list)) l)
)
)

l的更新值有错吗?此列表(a (b) (c d)) 的输出应为(1 2)

【问题讨论】:

  • 不,(fun '(a (b) (c d))) 返回(1 2)

标签: list lisp common-lisp nested-lists do-loops


【解决方案1】:

尝试用列表而不是数组来思考。您正在使用列表的第 n 个元素,就好像它是一个数组一样。相反,使用do,您可以通过每次获取下一个子列表来遍历列表,即删除第一个元素并获取另一个没有该第一个元素的列表。

(defun fun(list)
  (do ((l list (cdr l))
       (result nil) )
      ((null l) (nreverse result))
    (if (listp (car l))
      (push (length (car l)) result) )))

do 运算符接受三个参数:变量列表、结束条件和循环体。第一个包括变量的名称、它们的初始值以及(可选)它们如何从一个循环变为下一个循环。例如,(l list (cdr l)) 表示您使用变量l,其初始值为输入列表,并且从一个循环到下一个循环,它将成为自身的 cdr,即它将丢失其第一个元素。 结束条件还包括函数的返回值。对于((null l) (nreverse result)),我们说当变量l 为空时,函数将结束并返回值(nreverse result)。为什么要逆向?因为我们在 body 中使用 push,它以错误的顺序累积值。 最后,主体告诉函数将l 的第一个元素的长度添加到result,只要这是一个列表。

【讨论】:

  • DO 不是函数,而是特殊运算符
【解决方案2】:

遍历nested-list 中的所有项目。对于每个根据listp的列表,计算长度并收集。收集的长度列表是结果值:

(loop for item in nested-list
      if (listp item) collect (length item))

将每个元素 nested-list 传递给一个函数。对于每个列表项,该函数返回一个长度为一个元素的列表,否则返回空列表。将这些列表连接起来形成一个列表,然后返回。

(mapcan (lambda (x) (if (listp x) (list (length x)))) nested-list)

nested-list 中删除非列表项,生成一个只有列表的新列表。然后通过length函数映射这个列表,得到一个长度列表:

(mapcar #'length (remove-if-not #'listp nested-list))

【讨论】:

  • 只有代码的答案几乎总是可以通过添加一些关于它们的工作原理和原因的解释来改进?
  • 错字 - if (lisp item) 应该是 if (listp item) ?
  • @SurajKumar 这里没有特殊的技巧或算法;一些库功能(已详细记录)正在以基本方式使用。如果有人不打算自己做作业,他们至少应该自己研究勺子喂养的解决方案是如何工作的(以防他们被要求向教授解释他们的提交)。
  • @Kaz 仅代码答案可能会解决问题,但如果您解释它们如何解决问题,它们会更有用。社区需要理论和代码才能完全理解您的答案。这就是您的答案出现在审核中的原因。
  • @SurajKumar 我会试试的。
猜你喜欢
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多