在 Lisp 中找出等差级数的差异

Finding the difference in an arithmetic progression in Lisp

完全 Lisp 新手。

如何找出等差级数中元素之间的差异?

例如

(counted-by-N '(20 10 0))

Return -10

(counted-by-N '(20 10 5))
(counted-by-N '(2))
(counted-by-N '())

Returns Nil

在 Python/C 和其他语言中,它非常简单...有点卡在 Lisp 中。

我的伪算法是这样的:

function counted-by-N(L):
    if len(L) <= 1:
        return Nil
    else:
        diff = L[second] - L[first]
        for (i = second; i < len(L) - 1; i++):
            if L[i+1] - L[i] != diff
                return Nil
        return diff

当前工作:

(defun count-by-N (L)
    (if (<= (length L) 1) Nil
    (
        (defvar diff (- (second L) (first L)))
        ; How to do the loop part?
    ))
)
(flet ((by-n (list &aux
                   (e1 (first list))
                   (e2 (second list))
                   (difference (and e1 e2 (- e2 e1))))
         (and difference
              (loop for (one two) on list
                    while (and one two)
                    when (/= (- two one) difference)
                    do (return-from by-n nil)))
         difference))

  (by-n '(20 10 0)))

(flet ((by-n (list &aux
                   (e1 (first list))
                   (e2 (second list))
                   (difference (and e1 e2 (- e2 e1))))
         (when difference
           (loop for (one two) on list
                 while (and one two)
                 when (/= (- two one) difference)
                 do (return-from by-n nil))
           difference)))

  (by-n '(20 10 0)))

这是我使用递归对这个问题的最终答案:

(defun diff (N)
    (- (second N) (first N))
)

(defun count-by-N (L)
    (cond
        ((null L)          nil)
        ((= (length L) 1)  nil)
        ((= (length L) 2) (diff L))
        ((= (diff L) (diff (rest L))) (count-by-N (rest L)))
        (T nil)
    )
)

就你在第二个答案中所说的,你必须做这个例子的最佳选择是递归地实现它。

使用列表处理的示例(礼貌)

那样的话,您可以通过一些简单的递归方式来完成此示例:

(defun count-by-N-1 (lst)
  (if (equal NIL lst)
    NIL
    (- (car (cdr lst)) (car lst))
  )
  (count-by-N-1 (cdr lst))
)

在函数 count-by-N-1 的第一种方法中,我使用简单的 carcdr 指令来简化 Common Lisp 列表转换的基础知识。

使用列表处理快捷方式的示例(最佳实施)

但是你可以通过使用 carcdr 指令的一些快捷方式来恢复,比如当你想做一个 cdrcar 时,就像我做的那样在这个例子中:

(defun count-by-N-2 (lst)
  (if (equal NIL lst)
    NIL
    (- (cadr lst) (car lst))
  )
  (count-by-N-2 (cdr lst))
)

如果你在使用Common Lisp List转换的基本指令以及carcdr理解这类问题时,你仍然可以选择firstsecondrest 方法。但是,我建议您先查看一些基本说明:

http://www.gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html

使用访问器的示例(最适合理解)

(defun count-by-N-3 (lst)
  (if (equal NIL lst)
    NIL
    (- (first (rest lst)) (first lst))
  )
  (count-by-N-3 (rest lst))
)

最后一个,我将解释得更清楚,因为它是最容易理解的,您将进行递归列表操作(如其他示例中所示),并像其他示例一样,直到列表不是 NIL 它将获取列表其余部分的第一个元素并减去同一列表的第一个元素。该程序将为每个元素执行此操作,直到列表为 "clean"。最后 returns 减去值的列表。

这样,如果您阅读并研究了使用 firstsecondrest 方法与使用 carcdr 方法之间的相似之处,您很容易将理解我在这里放的前两个例子。