遍历列表并附加到新列表

Looping through a list and appending to a new one

我是 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)

应该不会太难吧?这是我到目前为止所拥有的。不过目前 returns NIL。有解决这个问题的想法吗?

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

既然你可以使用loop,那就简单地做

(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) return 是一个新列表,但它不会修改 coins-list;这就是为什么最终结果是 NIL。

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

然而,在 Lisp 的做事方式(函数式编程)中,我们尽量不修改那样的东西。相反,我们使每个表达式 return 成为一个基于输入值的值(一个新对象),然后将该新对象传递给另一个函数。通常,对象被传递给的函数与执行传递的函数是同一个函数;这就是递归。

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

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

节省了相当多的打字、手动积累到事物中,并且总体上相对可读。可以做更多的文档字符串,也许还有一些单元测试。