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)
不同。
其次,局部变量和全局变量之间有一个重要的区别。因此,在这两种情况下,您都需要 reversedList
和 count
的局部变量。这是棘手的一点。 Common Lisp 没有全局或局部变量,它有 dynamic
和 lexical
变量,它们并不完全相同。为了这些目的,我们可以使用词法变量,用 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
- 或者可以写成
let
、dolist
和incf
:
(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
我刚开始学习 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)
不同。
其次,局部变量和全局变量之间有一个重要的区别。因此,在这两种情况下,您都需要 reversedList
和 count
的局部变量。这是棘手的一点。 Common Lisp 没有全局或局部变量,它有 dynamic
和 lexical
变量,它们并不完全相同。为了这些目的,我们可以使用词法变量,用 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
orlet*
。 - 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
- 或者可以写成
let
、dolist
和incf
:
(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