列表

基础知识

可以使用 list 函数构建列表

CL-USER> (list 1 2 3)
(1 2 3)

可以使用 firstsecond,一直到 tenth 来访问列表中的对应元素

CL-USER> (first (list 1 2 3))
1

CL-USER> (second (list 1 2 3))
2

这些元素还可以用于设置元素

CL-USER> (defparameter my-list (list 1 2 3))
MY-LIST

CL-USER> (setf (second my-list) 7)
7

CL-USER> my-list
(1 7 3)

更一般的,可以使用 nth 函数

CL-USER> (nth 1 (list 1 2 3))
2

并且它适用于 setf

CL-USER> (defparameter my-list (list 1 2 3))
MY-LIST

CL-USER> (setf (nth 1 my-list) 65)
65

CL-USER> my-list
(1 65 3)

高阶函数

Map

map 函数接收一个函数和一个列表,遍历序列中的每个元素,并返回一个新列表,其中每个元素都是使用原始元素调用该函数的结果。

例如

CL-USER> (mapcar #'evenp (list 1 2 3 4 5 6))
(NIL T NIL T NIL T)

等同于

CL-USER> (list (evenp 1) (evenp 2) (evenp 3) (evenp 4) (evenp 5) (evenp 6))
(NIL T NIL T NIL T)

另一个例子

CL-USER> (mapcar #'string-upcase (list "Hello" "world!"))
("HELLO" "WORLD!")

帮助理解 mapcar 的一种方法是自己编写

CL-USER> (defun my-map (function list)
           (if list
               (cons (funcall function (first list))
                     (my-map function  (rest list)))
               nil))
MY-MAP

CL-USER> (my-map #'string-upcase (list "a" "b" "c"))
("A" "B" "C")

Reduce

reduce 函数可用于通过对列表的连续子集应用函数来将列表转换为标量。例如

CL-USER> (reduce #'+ (list 1 2 3))
6

你还可以使用自定义函数

CL-USER> (reduce #'(lambda (a b)
                     (* a b))
                 (list 10 20 30))
6000

以上等同于 (* 10 (* 20 (* 30)))。为了更好地理解 reduce 的工作原理,我们可以使用 format

CL-USER> (reduce #'(lambda (a b)
                     (format t "A: ~A, B: ~A~%" a b)
                     (* a b))
                 (list 1 2 3 4 5 6))
A: 1, B: 2
A: 2, B: 3
A: 6, B: 4
A: 24, B: 5
A: 120, B: 6
720

排序

sort 函数允许你对序列进行排序

CL-USER> (sort (list 9 2 4 7 3 0 8) #'<)
(0 2 3 4 7 8 9)

解构

(defun destructure (list)
  (destructuring-bind (first second &rest others)
    list
    (format t "First: ~A~%" first)
    (format t "Second: ~A~%" second)
    (format t "Rest: ~A~%" others)))

这会生成

CL-USER> (destructure (list 1 2 3 4 5 6))
First: 1
Second: 2
Rest: (3 4 5 6)
NIL