列表 #
一、列表简介 #
列表是Clojure(以及所有Lisp方言)最基础的数据结构。Clojure的列表是单向链表,适合在头部添加元素。
1.1 列表特点 #
- 单向链表结构
- 头部插入O(1)
- 随机访问O(n)
- 不可变、持久化
- 代码即数据
1.2 创建列表 #
clojure
'(1 2 3 4 5)
(list 1 2 3)
(list)
(list 1 2 3 4 5)
'()
clojure
(class '(1 2 3))
二、基本操作 #
2.1 访问元素 #
clojure
(def my-list '(1 2 3 4 5))
(first my-list)
(second my-list)
(rest my-list)
(next my-list)
(nth my-list 2)
(nth my-list 10)
(nth my-list 10 :not-found)
(last my-list)
2.2 first vs peek #
clojure
(first '(1 2 3))
(peek '(1 2 3))
(first '())
(peek '())
2.3 rest vs next #
clojure
(rest '(1 2 3))
(next '(1 2 3))
(rest '(1))
(next '(1))
(rest '())
(next '())
rest 返回空序列而不是nil,next 返回nil。
2.4 添加元素 #
clojure
(conj '(2 3 4) 1)
(cons 1 '(2 3 4))
(into '(3 4 5) '(1 2))
conj 对列表在头部添加元素。
三、列表函数 #
3.1 判断函数 #
clojure
(list? '(1 2 3))
(list? [1 2 3])
(list? '())
(empty? '())
(empty? '(1))
(seq? '(1 2 3))
(seq? [1 2 3])
3.2 列表构建 #
clojure
(list 1 2 3)
(list* 1 2 '(3 4 5))
(repeat 5 1)
(repeat 3 "hello")
(range 5)
(range 1 10)
(range 0 10 2)
(iterate inc 0)
(take 5 (iterate inc 0))
3.3 列表长度 #
clojure
(count '(1 2 3 4 5))
(count '())
四、列表遍历 #
4.1 map #
clojure
(map inc '(1 2 3 4 5))
(map #(* % %) '(1 2 3 4 5))
(map str '(1 2 3) '("a" "b" "c"))
4.2 filter #
clojure
(filter even? '(1 2 3 4 5 6))
(filter #(< % 4) '(1 2 3 4 5))
(remove odd? '(1 2 3 4 5))
4.3 reduce #
clojure
(reduce + '(1 2 3 4 5))
(reduce + 0 '(1 2 3 4 5))
(reduce conj '() '(1 2 3))
4.4 for #
clojure
(for [x '(1 2 3 4 5)]
(* x x))
(for [x '(1 2 3 4 5)
:when (even? x)]
x)
(for [x '(1 2 3)
y '(a b c)]
[x y])
五、列表与代码 #
5.1 代码即数据 #
Clojure代码本身就是列表:
clojure
(def code '(+ 1 2 3))
(eval code)
(first code)
(rest code)
(class code)
5.2 宏与列表 #
宏操作代码列表:
clojure
(defmacro when-let
[binding & body]
`(let [~binding]
(when ~'result
~@body)))
5.3 quote与syntax-quote #
clojure
'(+ 1 2)
`(+ 1 2)
(let [x 5]
`(+ ~x 1))
(let [x 5]
'(+ x 1))
六、列表与其他序列 #
6.1 转换为列表 #
clojure
(seq [1 2 3])
(seq {:a 1 :b 2})
(seq #{1 2 3})
(apply list [1 2 3])
(into '() [1 2 3])
6.2 列表vs向量 #
| 操作 | 列表 | 向量 |
|---|---|---|
| 头部添加 | O(1) | O(n) |
| 尾部添加 | O(n) | O(1) |
| 随机访问 | O(n) | O(1) |
| 创建语法 | '(1 2 3) |
[1 2 3] |
选择建议:
- 需要头部添加:使用列表
- 需要随机访问:使用向量
- 代码结构:使用列表
七、高级操作 #
7.1 split-at #
clojure
(split-at 3 '(1 2 3 4 5 6 7))
7.2 split-with #
clojure
(split-with #(< % 4) '(1 2 3 4 5 6))
7.3 partition #
clojure
(partition 2 '(1 2 3 4 5 6))
(partition 3 2 '(1 2 3 4 5 6 7 8))
(partition-all 3 '(1 2 3 4 5))
7.4 interleave #
clojure
(interleave '(1 2 3) '(a b c))
7.5 interpose #
clojure
(interpose 0 '(1 2 3 4 5))
八、常用模式 #
8.1 递归处理 #
clojure
(defn sum-list [lst]
(if (empty? lst)
0
(+ (first lst)
(sum-list (rest lst)))))
(sum-list '(1 2 3 4 5))
8.2 尾递归优化 #
clojure
(defn sum-list-tail [lst]
(loop [lst lst
acc 0]
(if (empty? lst)
acc
(recur (rest lst)
(+ acc (first lst))))))
(sum-list-tail '(1 2 3 4 5))
8.3 构建列表 #
clojure
(defn build-list [n]
(loop [i n
result '()]
(if (zero? i)
result
(recur (dec i)
(conj result i)))))
(build-list 5)
8.4 反转列表 #
clojure
(defn my-reverse [lst]
(reduce conj '() lst))
(my-reverse '(1 2 3 4 5))
九、实践示例 #
9.1 链表节点 #
clojure
(defn make-node [value next]
{:value value :next next})
(defn node-value [node]
(:value node))
(defn node-next [node]
(:next node))
(def my-linked-list
(make-node 1
(make-node 2
(make-node 3 nil))))
9.2 队列实现 #
clojure
(defn make-queue []
'())
(defn enqueue [queue item]
(concat queue (list item)))
(defn dequeue [queue]
{:item (first queue)
:queue (rest queue)})
(-> '()
(enqueue 1)
(enqueue 2)
(enqueue 3))
9.3 栈实现 #
clojure
(defn make-stack []
'())
(defn push [stack item]
(conj stack item))
(defn pop-stack [stack]
{:item (first stack)
:stack (rest stack)})
(defn peek-stack [stack]
(first stack))
(-> '()
(push 1)
(push 2)
(push 3))
十、总结 #
列表操作速查:
| 操作 | 函数 |
|---|---|
| 创建 | '(), list, list* |
| 头部 | first, peek |
| 尾部 | rest, next, pop |
| 添加 | conj, cons |
| 访问 | nth, last |
| 判断 | list?, empty?, seq? |
关键点:
- 列表是Lisp的核心数据结构
- 代码即数据,列表可以表示代码
- 头部操作高效,随机访问慢
restvsnext的区别- 使用
conj在头部添加元素
下一步,让我们学习向量!
最后更新:2026-03-27