TL;DR

  • Clojure のセット(集合)は、順序と重複を持たないコレクションで、clojure.lang.IPersistentSet インタフェースを実装している。
  • set や hash-set でハッシュセットを、sorted-set や sorted-set-by でソート済みのセットを作り、disj で要素を除外する。

内容

セットの作成と判定

set は、シーケンスやマップ、文字列などのコレクションをセットに変換する。重複した要素は 1 つにまとまる。set? は、引数が IPersistentSet を実装しているかを判定する。

(set [1 2 2 3 3])      ; #{1 3 2}
(set {:a 1 :b 2 :c 3}) ; #{[:c 3] [:b 2] [:a 1]}
(set "hello")          ; #{\e \h \l \o}
 
(map set? ['() [] #{} {}]) ; (false false true false)

hash-set は、引数をキーとする新しいハッシュセットを返す。重複するキーは自動で除かれ、引数がなければ空のセットを返す。set と同じく PersistentHashSet のインスタンスになる。

(hash-set 1 2 3)             ; #{1 3 2}
(hash-set [1 2] [2 3] [1 2]) ; #{[2 3] [1 2]}
(hash-set)                   ; #{}
 
(map type [(set [1]) (hash-set 1)])
;; (clojure.lang.PersistentHashSet clojure.lang.PersistentHashSet)

ソート済みのセット

sorted-set は、引数からソート済みのセット(PersistentTreeSet)を作る。conj で要素を足しても順序は保たれる。

(sorted-set 1 3 2 1)         ; #{1 2 3}
(sorted-set "b" "a" "c" "a") ; #{"a" "b" "c"}
 
(def s (sorted-set 1 2 3))
(conj s 4) ; #{1 2 3 4}

sorted-set-by は、比較関数を指定してソート済みのセットを作る。比較関数は 2 つの引数を受け取り、負の値を返せば左の引数が、正の値を返せば右の引数が小さいとみなされる。比較関数が等しいと判定した要素は重複として扱われるので、次の最後の例では "hello" と同じ長さの "world" が残らない。

(sorted-set-by > 3 1 4 1 5 9 2 6 5)                ; #{9 6 5 4 3 2 1}
(sorted-set-by #(compare %2 %1) 3 1 4 1 5 9 2 6 5) ; #{9 6 5 4 3 2 1}
 
(sorted-set-by #(compare (count %2) (count %1)) "hello" "world" "clojure" "java")
;; #{"clojure" "hello" "java"}

要素の除外

disj は、指定した要素を除いた新しいセットを返す。除く要素が見つからなくてもエラーにならない。

(disj #{1 2 3} 2)        ; #{1 3}
(disj #{:a :b :c} :b :c) ; #{:a}
(disj #{} 1)             ; #{}

キーワード