集合 #
一、集合简介 #
集合是Clojure中用于存储唯一值的数据结构,类似于数学中的集合概念。集合中的元素不重复,且没有顺序。
1.1 集合特点 #
- 元素唯一,无重复
- 无序存储
- 高效成员检测O(log32 n)
- 不可变、持久化
- 支持集合运算
1.2 创建集合 #
clojure
#{1 2 3 4 5}
#{:a :b :c}
(hash-set 1 2 3 2 1)
(set [1 2 3 2 1])
(set {:a 1 :b 2})
(into #{} [1 2 3 2 1])
(sorted-set 3 1 2 5 4)
#{}
clojure
(class #{1 2 3})
1.3 集合类型 #
| 类型 | 特点 | 创建方式 |
|---|---|---|
| HashSet | 无序,高效 | #{}, hash-set |
| SortedSet | 排序 | sorted-set |
二、基本操作 #
2.1 成员检测 #
clojure
(def s #{1 2 3 4 5})
(contains? s 3)
(contains? s 6)
(s 3)
(s 6)
(get s 3)
(get s 6)
(get s 6 :not-found)
2.2 添加元素 #
clojure
(def s #{1 2 3})
(conj s 4)
(conj s 4 5 6)
(into s [4 5 6])
2.3 删除元素 #
clojure
(def s #{1 2 3 4 5})
(disj s 3)
(disj s 3 4 5)
2.4 集合大小 #
clojure
(count #{1 2 3 4 5})
(count #{})
三、集合函数 #
3.1 判断函数 #
clojure
(set? #{1 2 3})
(set? [1 2 3])
(empty? #{})
(empty? #{1})
3.2 集合作为函数 #
集合本身可以作为谓词函数:
clojure
(def vowels #{\a \e \i \o \u})
(filter vowels "hello world")
(remove vowels "hello world")
(some vowels "xyz")
3.3 转换为集合 #
clojure
(set [1 2 3 2 1])
(set '(1 2 3 2 1))
(set {:a 1 :b 2})
(set "hello")
四、集合运算 #
需要引入 clojure.set:
clojure
(require '[clojure.set :as set])
4.1 并集 #
clojure
(set/union #{1 2 3} #{3 4 5})
(set/union #{1 2} #{3 4} #{5 6})
(set/union #{1 2 3})
4.2 交集 #
clojure
(set/intersection #{1 2 3 4} #{3 4 5 6})
(set/intersection #{1 2 3} #{4 5 6})
(set/intersection #{1 2 3})
4.3 差集 #
clojure
(set/difference #{1 2 3 4 5} #{3 4})
(set/difference #{1 2 3} #{1 2 3})
(set/difference #{1 2 3} #{4 5 6})
4.4 子集判断 #
clojure
(set/subset? #{1 2} #{1 2 3 4})
(set/subset? #{1 2 5} #{1 2 3 4})
(set/superset? #{1 2 3 4} #{1 2})
(set/superset? #{1 2 3} #{1 2 5})
4.5 对称差 #
clojure
(defn symmetric-difference [a b]
(set/difference (set/union a b)
(set/intersection a b)))
(symmetric-difference #{1 2 3} #{2 3 4})
五、集合遍历 #
5.1 map #
clojure
(map inc #{1 2 3 4 5})
(into #{} (map inc #{1 2 3 4 5}))
5.2 filter #
clojure
(filter even? #{1 2 3 4 5 6})
(into #{} (filter even? #{1 2 3 4 5 6}))
5.3 reduce #
clojure
(reduce + #{1 2 3 4 5})
(reduce conj #{} [1 2 3])
5.4 for #
clojure
(for [x #{1 2 3 4 5}
:when (even? x)]
(* x x))
六、高级操作 #
6.1 join #
clojure
(def users #{{:id 1 :name "Alice"}
{:id 2 :name "Bob"}})
(def orders #{{:user-id 1 :product "Book"}
{:user-id 1 :product "Pen"}
{:user-id 2 :product "Paper"}})
(set/join users orders {:id :user-id})
6.2 project #
clojure
(set/project #{{:a 1 :b 2 :c 3}
{:a 4 :b 5 :c 6}}
[:a :b])
6.3 select #
clojure
(set/select #(> (:age %) 25)
#{{:name "Alice" :age 30}
{:name "Bob" :age 20}
{:name "Carol" :age 35}})
6.4 rename #
clojure
(set/rename #{{:a 1 :b 2}} {:a :alpha :b :beta})
6.5 index #
clojure
(set/index #{{:a 1 :b 2} {:a 1 :b 3} {:a 2 :b 4}} [:a])
七、SortedSet #
7.1 创建SortedSet #
clojure
(def ss (sorted-set 3 1 4 1 5 9 2 6))
ss
(class ss)
7.2 范围操作 #
clojure
(subseq ss > 3)
(subseq ss >= 3 <= 5)
(rsubseq ss < 5)
7.3 边界操作 #
clojure
(def ss (sorted-set 1 3 5 7 9))
(first ss)
(last ss)
八、实践示例 #
8.1 去重 #
clojure
(defn unique [coll]
(set coll))
(unique [1 2 3 2 1 4 3 5])
(defn unique-by [f coll]
(into #{} (map f) coll))
(unique-by :id [{:id 1 :name "A"}
{:id 2 :name "B"}
{:id 1 :name "C"}])
8.2 标签系统 #
clojure
(def articles
[{:id 1 :tags #{:clojure :programming}}
{:id 2 :tags #{:clojure :functional}}
{:id 3 :tags #{:java :programming}}])
(defn find-by-tag [articles tag]
(filter #(contains? (:tags %) tag) articles))
(find-by-tag articles :clojure)
(defn find-by-any-tag [articles tags]
(filter #(some (:tags %) tags) articles))
(find-by-any-tag articles #{:functional :java})
8.3 权限系统 #
clojure
(def user-permissions #{:read :write})
(def required-permissions #{:read :write :delete})
(defn can-access? [user-perms required]
(set/subset? required user-perms))
(can-access? user-permissions required-permissions)
(defn has-any-permission? [user-perms required]
(not (empty? (set/intersection user-perms required))))
(has-any-permission? user-permissions #{:read :admin})
8.4 数据对比 #
clojure
(defn compare-collections [a b]
(let [set-a (set a)
set-b (set b)]
{:only-in-a (set/difference set-a set-b)
:only-in-b (set/difference set-b set-a)
:in-both (set/intersection set-a set-b)}))
(compare-collections [1 2 3 4] [3 4 5 6])
8.5 找出重复元素 #
clojure
(defn find-duplicates [coll]
(let [freqs (frequencies coll)]
(set (for [[k v] freqs
:when (> v 1)]
k))))
(find-duplicates [1 2 3 2 4 3 5 3])
九、性能考虑 #
9.1 成员检测 #
clojure
(def v (vec (range 1000000)))
(def s (set v))
(time (contains? s 999999))
(time (some #{999999} v))
集合的成员检测比向量快得多。
9.2 选择合适的数据结构 #
| 操作 | 集合 | 向量 | 映射 |
|---|---|---|---|
| 成员检测 | O(log32 n) | O(n) | O(log32 n) |
| 添加 | O(log32 n) | O(1) | O(log32 n) |
| 随机访问 | 不支持 | O(log32 n) | O(log32 n) |
十、总结 #
集合操作速查:
| 操作 | 函数 |
|---|---|
| 创建 | #{}, hash-set, set |
| 检测 | contains?, (s x), get |
| 添加 | conj, into |
| 删除 | disj |
| 并集 | set/union |
| 交集 | set/intersection |
| 差集 | set/difference |
| 子集 | set/subset?, set/superset? |
关键点:
- 集合存储唯一值
- 成员检测高效
- 集合可作为谓词函数
clojure.set提供集合运算sorted-set保持排序
Clojure数据结构系列完成!接下来学习函数!
最后更新:2026-03-27