# Sets store ... well sets
empty_set = set()
# Initialize a set with a bunch of values.
some_set = {1, 1, 2, 2, 3, 4} # some_set is now {1, 2, 3, 4}
# Similar to keys of a dictionary, elements of a set have to be immutable.
invalid_set = {[1], 1} # => Raises a TypeError: unhashable type: 'list'
valid_set = {(1,), 1}
# Add one more item to the set
filled_set = some_set
filled_set.add(5) # filled_set is now {1, 2, 3, 4, 5}
# Sets do not have duplicate elements
filled_set.add(5) # it remains as before {1, 2, 3, 4, 5}
# Do set intersection with &
other_set = {3, 4, 5, 6}
filled_set & other_set # => {3, 4, 5}
# Do set union with |
filled_set | other_set # => {1, 2, 3, 4, 5, 6}
# Do set difference with -
{1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
# Do set symmetric difference with ^
{1, 2, 3, 4} ^ {2, 3, 5} # => {1, 4, 5}
# Check if set on the left is a superset of set on the right
{1, 2} >= {1, 2, 3} # => False
# Check if set on the left is a subset of set on the right
{1, 2} <= {1, 2, 3} # => True
# Check for existence in a set with in
2 in filled_set # => True
10 in filled_set # => False
# Make a one layer deep copy
filled_set = some_set.copy() # filled_set is {1, 2, 3, 4, 5}
filled_set is some_set # => False
|
;; Sets store ... well, something akin to sets using hash tables
(setq empty-set (make-hash-table :test 'equal))
;; Initialize a "set" with a bunch of values
(setq some-set (make-hash-table :test 'equal))
(mapc (lambda (x) (puthash x t some-set)) '(1 1 2 2 3 4)) ;; some-set is now effectively {1, 2, 3, 4}
;; Similar to keys of a dictionary, elements of a "set" have to be comparable with the test function.
;; Invalid "set" construction would cause errors if attempted with non-hashable types.
;; This is an invalid line in Emacs Lisp and commented out:
;; (setq invalid-set (make-hash-table :test 'equal))
;; (puthash [1] t invalid-set) ;; Would raise an error in a hypothetical correct context
(setq valid-set (make-hash-table :test 'equal))
(puthash (list 1) t valid-set)
(puthash 1 t valid-set)
;; Add one more item to the "set"
(setq filled-set some-set)
(puthash 5 t filled-set) ;; filled-set is now effectively {1, 2, 3, 4, 5}
(puthash 5 t filled-set) ;; it remains as before {1, 2, 3, 4, 5}
;; Set operations using hash tables require custom functions or cl-lib utilities:
;; Intersection (set1 & set2)
(setq other-set (make-hash-table :test 'equal))
(mapc (lambda (x) (puthash x t other-set)) '(3 4 5 6))
(setq intersection-set (cl-intersection (hash-table-keys filled-set) (hash-table-keys other-set) :test 'equal))
;; Union (set1 | set2)
(setq union-set (cl-union (hash-table-keys filled-set) (hash-table-keys other-set) :test 'equal))
;; Difference (set1 - set2)
(setq difference-set (cl-set-difference (hash-table-keys filled-set) (hash-table-keys other-set) :test 'equal))
;; Symmetric Difference (set1 ^ set2)
(setq symmetric-difference-set (cl-set-exclusive-or (hash-table-keys filled-set) (hash-table-keys other-set) :test 'equal))
;; Superset check
(cl-subsetp (hash-table-keys other-set) (hash-table-keys filled-set) :test 'equal) ;; => nil (false, filled-set is not a superset)
;; Subset check
(cl-subsetp (hash-table-keys '(1 2)) (hash-table-keys '(1 2 3)) :test 'equal) ;; => t (true, {1, 2} is a subset of {1, 2, 3})
;; Check for existence in a "set" with `gethash`
(gethash 2 filled-set) ;; => t (true)
(gethash 10 filled-set) ;; => nil (false)
;; Make a one layer deep copy
(setq filled-set-copy (make-hash-table :test 'equal))
(maphash (lambda (k v) (puthash k v filled-set-copy)) filled-set)
(eq filled-set filled-set-copy) ;; => nil
|