集合 #

一、集合简介 #

集合是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?

关键点:

  1. 集合存储唯一值
  2. 成员检测高效
  3. 集合可作为谓词函数
  4. clojure.set 提供集合运算
  5. sorted-set 保持排序

Clojure数据结构系列完成!接下来学习函数!

最后更新:2026-03-27