Lisp 循环浏览列表并附加到新列表

Lisp 循环浏览列表并附加到新列表,lisp,common-lisp,Lisp,Common Lisp,我是Lisp的新手。我正在尝试编写一个函数,它将获取一个虚线列表(表示某个值的硬币数量),例如 然后将其转换为按价值列出每枚硬币,例如 ((1 . 50) (2 . 20) (3 . 10)) ;; one 50 cent coin, two 20 cent coins, three 10 cent coins (50 20 20 10 10 10) 应该不会太难吧?这就是我目前所拥有的。不过,目前它返回零。有没有办法解决这个问题 (defun fold-out (coins) (let

我是Lisp的新手。我正在尝试编写一个函数,它将获取一个虚线列表(表示某个值的硬币数量),例如

然后将其转换为按价值列出每枚硬币,例如

((1 . 50) (2 . 20) (3 . 10)) ;; one 50 cent coin, two 20 cent coins, three 10 cent coins
(50 20 20 10 10 10)
应该不会太难吧?这就是我目前所拥有的。不过,目前它返回零。有没有办法解决这个问题

(defun fold-out (coins)
  (let ((coins-list (list)))
    (dolist (x coins)
      (let ((quantity (car x)) (amount (cdr x)))
        (loop for y from 0 to quantity
          do (cons amount coins-list))))
   coins-list))

由于您可以使用
循环
,只需

(defun fold-out (coins)
  (loop 
    for (quantity . amount) in coins
    nconc (make-list quantity :initial-element amount)))
或者,使用
dolist

(defun fold-out (coins)
  (let ((rcoins (reverse coins)) (res nil))
    (dolist (c rcoins)
      (let ((quantity (car c)) (amount (cdr c)))
        (dotimes (j quantity) (push amount res))))
    res))

由于您可以使用
循环
,只需

(defun fold-out (coins)
  (loop 
    for (quantity . amount) in coins
    nconc (make-list quantity :initial-element amount)))
或者,使用
dolist

(defun fold-out (coins)
  (let ((rcoins (reverse coins)) (res nil))
    (dolist (c rcoins)
      (let ((quantity (car c)) (amount (cdr c)))
        (dotimes (j quantity) (push amount res))))
    res))
表达式
(cons amount coins list)
返回一个新列表,但它不修改
coins list
;这就是最终结果为零的原因

因此,您可以将其更改为
(setf coins list(cons amount coins list))
,这将显式修改
coins list
,这将起作用

然而,在Lisp的工作方式(函数式编程)中,我们尽量不修改类似的内容。相反,我们让每个表达式返回一个基于输入值的值(一个新对象),然后将该新对象传递给另一个函数。通常,对象被传递到的函数与进行传递的函数相同;这是递归。

表达式
(cons amount coins list)
返回一个新列表,但它不会修改
coins list
;这就是最终结果为零的原因

因此,您可以将其更改为
(setf coins list(cons amount coins list))
,这将显式修改
coins list
,这将起作用


然而,在Lisp的工作方式(函数式编程)中,我们尽量不修改类似的内容。相反,我们让每个表达式返回一个基于输入值的值(一个新对象),然后将该新对象传递给另一个函数。通常,对象被传递到的函数与进行传递的函数相同;这就是递归。

如果要这样做,我可能会使用嵌套循环:

(defun fold-out (coins)
  (loop for (count . value) in coins
     append (loop repeat count
                  collect value)))

节省了大量的打字和手工积累,总体而言,相对可读。可以使用更多的docstring,或者一些单元测试。

如果要这样做,我可能会使用嵌套循环:

(defun fold-out (coins)
  (loop for (count . value) in coins
     append (loop repeat count
                  collect value)))

节省了大量的打字和手工积累,总体而言,相对可读。需要更多的docstring,也许还需要一些单元测试。

谢谢。这两种解决方案都非常有用,因为我刚刚熟悉了这门语言。不客气,您已经非常接近了:将
cons
替换为
push
,以及
循环。。。使用
循环执行
。。。下面是初始代码中的
循环重复次数
,结果应该是正确的(尽管相反)。啊哈,太好了。现在查看
ncoc
的文档,我发现它是一个连接列表的函数。但是在上面的解决方案中,一次只调用一个参数。。。那么连接发生在哪里呢?是循环宏在处理它吗?很高兴看到有人浏览代码,而不是仅仅为了一些任务而复制粘贴代码
ncoc
这里是
循环
宏的关键字,而不是函数本身。因此,是的,宏正在处理对
ncoc
函数的正确调用。好的,这是有意义的。尤其是因为
ncoc
前面没有括号。而这实际上并不是一项任务;不久前,我偶然发现保罗·格雷厄姆的Lisp课本,从那以后我一直在学习。真有趣!至少比一些Algol类型的语言有趣多了。谢谢。这两种解决方案都非常有用,因为我刚刚熟悉了这门语言。不客气,您已经非常接近了:将
cons
替换为
push
,以及
循环。。。使用
循环执行
。。。下面是初始代码中的
循环重复次数
,结果应该是正确的(尽管相反)。啊哈,太好了。现在查看
ncoc
的文档,我发现它是一个连接列表的函数。但是在上面的解决方案中,一次只调用一个参数。。。那么连接发生在哪里呢?是循环宏在处理它吗?很高兴看到有人浏览代码,而不是仅仅为了一些任务而复制粘贴代码
ncoc
这里是
循环
宏的关键字,而不是函数本身。因此,是的,宏正在处理对
ncoc
函数的正确调用。好的,这是有意义的。尤其是因为
ncoc
前面没有括号。而这实际上并不是一项任务;不久前,我偶然发现保罗·格雷厄姆的Lisp课本,从那以后我一直在学习。真有趣!至少比一些Algol类型的语言有趣多了。