我是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)
不应该太难,对吗?这就是我到目前为止所拥有的。不过,它现在返回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))
答案 0 :(得分:3)
由于您可以使用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))
答案 1 :(得分:2)
如果我这样做,我可能会使用嵌套循环:
Sub urgent()
Dim rw As Long, str As String
With Worksheets("Sheet2") '<~~ set this worksheet reference properly!
For rw = .Cells(Rows.Count, "A").End(xlUp).Row To 1 Step -1
If IsNumeric(.Cells(rw, "A")) Then
If CBool(Len(str)) Then
.Cells(rw, "B").Resize(1, UBound(Split(str, ChrW(8203)))) = _
Split(str, ChrW(8203))
End If
str = vbNullString
Else
str = .Cells(rw, "A").Value2 & ChrW(8203) & str
.Rows(rw).EntireRow.Delete
End If
Next rw
For v = .Cells(2, 1).CurrentRegion.Columns.Count To 1 Step -1
.Columns(v).AutoFit
Next v
End With
End Sub
节省了大量的打字,手动积累到东西,总的来说,相对可读。可以使用更多文档字符串,也许还有一些单元测试。
答案 2 :(得分:1)
表达式(cons amount coins-list)
会返回一个新列表,但它不会修改coins-list
;这就是为什么最终结果是NIL。
因此,您可以将其更改为(setf coins-list (cons amount coins-list))
,这将明确修改coins-list
,这将有效。
然而,在Lisp的做事方式(函数式编程)中,我们尽量不修改那样的东西。相反,我们使每个表达式返回一个值(一个新对象),该值构建在输入值上,然后将该新对象传递给另一个函数。通常,对象传递给的函数与传递函数相同;那个递归。