Lisp 嵌套列表迭代

Lisp nested list iteration

我刚开始学习 Common Lisp,这是我的第一门函数式编程语言。 我正在尝试学习遍历列表。我写了这两个函数:

(defun reverseList (liste)
    (defvar reversedList(list))
    (loop for i downfrom (-(length liste)1) to 0 do
     (setf reversedList (append reversedList (list(nth i liste)))))
    reversedList ;return
)


(defun countAppearance(liste element)
    (defvar count 0)
    (loop for i from 0 to (-(length liste) 1)do
        (if (= (nth i liste) element)
            (setf count (+ count 1))))
    count
)

两者都适用于常规列表(例如:(1 3 5 7 3 9),但我希望它们也适用于嵌套列表。

示例:

countAppearance - 输入:(1 (3 5) (3 7 8) 2) 3 -> 预期 output:2

reverseList - 输入:(1 (2 3)) -> 预期输出:((3 2) 1)

欢迎使用函数式编程。

首先,您提供给我们的代码存在一些问题。代码中缺少一些空格。空格很重要,因为它们将一件事与另一件事分开。代码 (xy)(x y) 不同。

其次,局部变量和全局变量之间有一个重要的区别。因此,在这两种情况下,您都需要 reversedListcount 的局部变量。这是棘手的一点。 Common Lisp 没有全局或局部变量,它有 dynamiclexical 变量,它们并不完全相同。为了这些目的,我们可以使用词法变量,用 let 引入。关键字 let 在许多函数式语言中用于局部变量。此外,defvar 可能不会按照您的预期进行,因为它是一次写入值的方式,无法覆盖 - 我怀疑 defparameter 就是您的意思。

第三,看看反向函数,循环有自己的方式将结果收集到一个名为 collect 的列表中。这将是一个更清洁的解决方案。

(defun my-reverse (lst)
   (loop for x from (1- (length lst)) downto 0 collect (nth x lst)))

也可以用尾递归的方式来完成。

(defun my-reverse-tail (lst &optional (result '()))
   (if lst
      (my-reverse-tail (rest lst) (cons (first lst) result))
      result))

要使其与嵌套列表一起使用,在收集或使用每个值之前,您需要使用 listp 检查它是否是一个列表。如果它不是列表,只需将其添加到结果中即可。如果它是一个列表,请添加对项目的反向函数的调用。

Loop 还具有计算项目的功能。

在我向您展示嵌套列表的解决方案之前,请注意您的代码:

  • 已经有针对非嵌套列表的函数 reverse,因此您不必重新发明轮子。
=> (reverse (list 1 2 3 4 5))
(5 4 3 2 1)
  • 如果你需要一些局部变量,使用let or let*
  • Lisp 使用 kebab-case,而不是 camelCase,所以将 reverseList 重命名为 reverse-list 等等.
  • 对于(setf ... (+ ... 1)),使用incf
  • 要遍历列表,请使用 dolist
  • 函数count-occurrences可以用递归写成:
(defun count-occurrences (lst elem)
  (cond ((null lst) 0)
        ((= (car lst) elem) (+ 1 (count-occurrences (cdr lst) elem)))
        (t (count-occurrences (cdr lst) elem))))

CL-USER 3 > (count-occurrences (list 1 2 3 1 2 3) 2)
2
  • 或者可以写成letdolistincf
(defun count-occurrences2 (lst elem)
  (let ((count 0))
    (dolist (e lst)
      (when (= e elem) (incf count)))
    count))

CL-USER 4 > (count-occurrences2 (list 1 2 3 1 2 3) 2)
2

嵌套列表的解决方案使用递归:

(defun deep-reverse (o)
  (if (listp o) 
      (reverse (mapcar #'deep-reverse o))
    o))

CL-USER 11 > (deep-reverse '(1 (2 3)))
((3 2) 1)

(defun deep-count (lst elem)
  (cond ((null lst) 0)
        ((listp (car lst)) (+ (deep-count (car lst) elem)
                              (deep-count (cdr lst) elem)))
        ((= (car lst) elem) (+ 1 (deep-count (cdr lst) elem)))
        (t (deep-count (cdr lst) elem))))

CL-USER 12 > (deep-count '(1 (3 5) (3 7 8) 2) 3)
2