Browse Learn Clojure Foundations as a Java Developer

Sets in Clojure

Use Clojure sets for uniqueness, membership checks, set algebra, deduplication, and Java Set comparisons while preserving immutable value semantics.

Sets represent membership and uniqueness. If the question is “is this value present?” or “what values are unique?”, a set is usually the clearest Clojure collection.

1(def roles #{:admin :editor :viewer})

Like vectors and maps, Clojure sets are immutable persistent values. Adding or removing a member returns a new set.

Creating and Updating Sets

 1(def ids #{101 102 103})
 2
 3(conj ids 104)
 4;; => #{101 102 103 104}
 5
 6(conj ids 102)
 7;; => #{101 102 103}
 8
 9(disj ids 102)
10;; => #{101 103}
11
12ids
13;; => #{101 102 103}

Adding a duplicate does not change the set. Removing a missing element is safe and returns an equivalent set.

Membership

Use contains? for membership:

1(contains? roles :admin)
2;; => true
3
4(contains? roles :guest)
5;; => false

Sets can also be invoked as functions:

1(roles :editor)
2;; => :editor

Use contains? when you need a boolean answer, especially if the set may contain nil or false.

Java Set Comparison

Java Set habit Clojure set form Difference
set.add(x) (conj s x) Returns a new set
set.remove(x) (disj s x) Returns a new set
set.contains(x) (contains? s x) Value-oriented membership check
retainAll clojure.set/intersection Returns a new set
addAll clojure.set/union Returns a new set
removeAll clojure.set/difference Returns a new set

Java sets are mutable objects by default. Clojure sets are values by default.

Set Algebra

Require clojure.set:

1(require '[clojure.set :as set])

Then use ordinary set operations:

 1(def backend #{:java :clojure :sql})
 2(def data-team #{:clojure :python :sql})
 3
 4(set/union backend data-team)
 5;; => #{:java :clojure :sql :python}
 6
 7(set/intersection backend data-team)
 8;; => #{:clojure :sql}
 9
10(set/difference backend data-team)
11;; => #{:java}

Deduplication

Use set to remove duplicates when order is not important:

1(set [1 1 2 3 3])
2;; => #{1 2 3}

If order matters, use distinct:

1(distinct [1 1 2 3 3])
2;; => (1 2 3)

Choose deliberately. Sets do not promise insertion order.

Sets as Predicates

Sets work well as predicates in filters:

1(def allowed-statuses #{:draft :submitted :paid})
2
3(filter allowed-statuses [:draft :archived :paid])
4;; => (:draft :paid)

That works because a set returns the member when present and nil when absent. Again, use contains? when the result must be a strict boolean or when members could be falsey.

Choosing Sets

Use a set when… Use something else when…
You need uniqueness You need stable order
Membership is the main operation Position/index matters
You are comparing groups You need key-value data
You want a predicate of allowed values Values may be nil or false and boolean precision matters

Practice

  1. Build a set of allowed statuses and use it to filter a vector.
  2. Compare (set xs) and (distinct xs) for a vector with duplicates.
  3. Use set/intersection to find shared permissions between two users.
  4. Explain why (contains? #{nil} nil) is clearer than calling the set as a function.

Key Takeaways

  • Sets model uniqueness and membership.
  • conj and disj return new sets.
  • Use contains? for boolean membership checks.
  • Use clojure.set for union, intersection, and difference.
  • Sets are unordered; use distinct when order preservation matters.

Quiz: Sets in Clojure

### What is the primary purpose of a set? - [x] Membership and uniqueness. - [ ] Indexed access. - [ ] Key-value lookup. - [ ] Code evaluation. > **Explanation:** Sets answer membership questions and ensure unique values. ### What does `(conj #{1 2} 2)` return? - [x] `#{1 2}` - [ ] `#{1 2 2}` - [ ] `[1 2 2]` - [ ] `nil` > **Explanation:** Sets cannot contain duplicate members. ### Which function removes a value from a set? - [x] `disj` - [ ] `dissoc` - [ ] `rest` - [ ] `subvec` > **Explanation:** `disj` returns a set without the given member. ### Which operation finds shared members of two sets? - [x] `clojure.set/intersection` - [ ] `clojure.set/union` - [ ] `conj` - [ ] `assoc` > **Explanation:** Intersection returns members present in all input sets. ### True or False: Sets preserve insertion order. - [ ] True - [x] False > **Explanation:** Clojure sets are for uniqueness and membership, not insertion order.
Revised on Saturday, May 23, 2026