循环遍历列表并附加到新列表

时间:2015-11-08 15:45:06

标签: 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)

不应该太难,对吗?这就是我到目前为止所拥有的。不过,它现在返回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))

3 个答案:

答案 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的做事方式(函数式编程)中,我们尽量不修改那样的东西。相反,我们使每个表达式返回一个值(一个新对象),该值构建在输入值上,然后将该新对象传递给另一个函数。通常,对象传递给的函数与传递函数相同;那个递归。