# std/sets

Dark Mode

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

The `sets` module implements an efficient hash set and ordered hash set.

Hash sets are different from the built in set type. Sets allow you to store any value that can be hashed and they don't contain duplicate entries.

Common usages of sets:

- removing duplicates from a container by converting it with toHashSet proc (see also sequtils.deduplicate func)
- membership testing
- mathematical operations on two sets, such as union, intersection, difference, and symmetric difference

    echo toHashSet([9, 5, 1])     # {9, 1, 5}
    echo toOrderedSet([9, 5, 1])  # {9, 5, 1}

    let
      s1 = toHashSet([9, 5, 1])
      s2 = toHashSet([3, 5, 7])

    echo s1 + s2    # {9, 1, 3, 5, 7}
    echo s1 - s2    # {1, 9}
    echo s1 * s2    # {5}
    echo s1 -+- s2  # {9, 1, 3, 7}

Note: The data types declared here have value semantics: This means that `=` performs a copy of the set.

See also:

- intsets module for efficient int sets
- tables module for hash tables

# Imports

hashes, math

# Types

    HashSet[A] {..} = object
      data: KeyValuePairSeq[A]
      counter: int

  A generic hash set.

  Use init proc or initHashSet proc before calling other procs on it.

  Source Edit

    OrderedSet[A] {..} = object
      data: OrderedKeyValuePairSeq[A]
      counter, first, last: int

  A generic hash set that remembers insertion order.

  Use init proc or initOrderedSet proc before calling other procs on it.

  Source Edit

    SomeSet[A] = HashSet[A] | OrderedSet[A]

  Type union representing `HashSet` or `OrderedSet`. Source Edit

# Consts

    defaultInitialSize = 64

  Source Edit

# Procs

    proc `$`[A](s: HashSet[A]): string

  Converts the set `s` to a string, mostly for logging and printing purposes.

  Don't use this proc for serialization, the representation may change at any moment and values are not escaped.

  Examples:

      echo toHashSet([2, 4, 5])
      # --> {2, 4, 5}
      echo toHashSet(["no", "esc'aping", "is \" provided"])
      # --> {no, esc'aping, is " provided}

  Source Edit

    proc `$`[A](s: OrderedSet[A]): string

  Converts the ordered hash set `s` to a string, mostly for logging and printing purposes.

  Don't use this proc for serialization, the representation may change at any moment and values are not escaped.

  Examples:

      echo toOrderedSet([2, 4, 5])
      # --> {2, 4, 5}
      echo toOrderedSet(["no", "esc'aping", "is \" provided"])
      # --> {no, esc'aping, is " provided}

  Source Edit

    proc `*`[A](s1, s2: HashSet[A]): HashSet[A] {.inline.}

  Alias for intersection(s1, s2). Source Edit

    proc `+`[A](s1, s2: HashSet[A]): HashSet[A] {.inline.}

  Alias for union(s1, s2). Source Edit

    proc `-+-`[A](s1, s2: HashSet[A]): HashSet[A] {.inline.}

  Alias for symmetricDifference(s1, s2). Source Edit

    proc `-`[A](s1, s2: HashSet[A]): HashSet[A] {.inline.}

  Alias for difference(s1, s2). Source Edit

    proc `<=`[A](s, t: HashSet[A]): bool

  Returns true if `s` is a subset of `t`.

  A subset `s` has all of its members in `t` and `t` doesn't necessarily have more members than `s`. That is, `s` can be equal to `t`.

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = intersection(a, b)
      assert c <= a and c <= b
      assert a <= a

  Source Edit

    proc `<`[A](s, t: HashSet[A]): bool

  Returns true if `s` is a strict or proper subset of `t`.

  A strict or proper subset `s` has all of its members in `t` but `t` has more elements than `s`.

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = intersection(a, b)
      assert c < a and c < b
      assert(not (a < a))

  Source Edit

    proc `==`[A](s, t: HashSet[A]): bool

  Returns true if both `s` and `t` have the same members and set size.

  Example:

      var
        a = toHashSet([1, 2])
        b = toHashSet([2, 1])
      assert a == b

  Source Edit

    proc `==`[A](s, t: OrderedSet[A]): bool

  Equality for ordered sets.

  Example:

      let
        a = toOrderedSet([1, 2])
        b = toOrderedSet([2, 1])
      assert(not (a == b))

  Source Edit

    proc `[]`[A](s: var HashSet[A]; key: A): var A

  Returns the element that is actually stored in `s` which has the same value as `key` or raises the `KeyError` exception.

  This is useful when one overloaded `hash` and `==` but still needs reference semantics for sharing.

  Source Edit

    proc card[A](s: HashSet[A]): int

  Alias for len().

  Card stands for the cardinality of a set.

  Source Edit

    proc card[A](s: OrderedSet[A]): int {.inline.}

  Alias for len().

  Card stands for the cardinality of a set.

  Source Edit

    proc clear[A](s: var HashSet[A])

  Clears the HashSet back to an empty state, without shrinking any of the existing storage.

  `O(n)` operation, where `n` is the size of the hash bucket.

  See also:

  - pop proc

  Example:

      var s = toHashSet([3, 5, 7])
      clear(s)
      assert len(s) == 0

  Source Edit

    proc clear[A](s: var OrderedSet[A])

  Clears the OrderedSet back to an empty state, without shrinking any of the existing storage.

  `O(n)` operation where `n` is the size of the hash bucket.

  Example:

      var s = toOrderedSet([3, 5, 7])
      clear(s)
      assert len(s) == 0

  Source Edit

    proc contains[A](s: HashSet[A]; key: A): bool

  Returns true if `key` is in `s`.

  This allows the usage of `in` operator.

  See also:

  - incl proc
  - containsOrIncl proc

  Example:

      var values = initHashSet[int]()
      assert(not values.contains(2))
      assert 2 notin values

      values.incl(2)
      assert values.contains(2)
      assert 2 in values

  Source Edit

    proc contains[A](s: OrderedSet[A]; key: A): bool

  Returns true if `key` is in `s`.

  This allows the usage of `in` operator.

  See also:

  - incl proc
  - containsOrIncl proc

  Example:

      var values = initOrderedSet[int]()
      assert(not values.contains(2))
      assert 2 notin values

      values.incl(2)
      assert values.contains(2)
      assert 2 in values

  Source Edit

    proc containsOrIncl[A](s: var HashSet[A]; key: A): bool

  Includes `key` in the set `s` and tells if `key` was already in `s`.

  The difference with regards to the incl proc is that this proc returns `true` if `s` already contained `key`. The proc will return `false` if `key` was added as a new value to `s` during this call.

  See also:

  - incl proc for including an element
  - incl proc for including other set
  - missingOrExcl proc

  Example:

      var values = initHashSet[int]()
      assert values.containsOrIncl(2) == false
      assert values.containsOrIncl(2) == true
      assert values.containsOrIncl(3) == false

  Source Edit

    proc containsOrIncl[A](s: var OrderedSet[A]; key: A): bool

  Includes `key` in the set `s` and tells if `key` was already in `s`.

  The difference with regards to the incl proc is that this proc returns `true` if `s` already contained `key`. The proc will return false if `key` was added as a new value to `s` during this call.

  See also:

  - incl proc for including an element
  - missingOrExcl proc

  Example:

      var values = initOrderedSet[int]()
      assert values.containsOrIncl(2) == false
      assert values.containsOrIncl(2) == true
      assert values.containsOrIncl(3) == false

  Source Edit

    proc difference[A](s1, s2: HashSet[A]): HashSet[A]

  Returns the difference of the sets `s1` and `s2`.

  The same as s1 - s2.

  The difference of two sets is represented mathematically as A ∖ B and is the set of all objects that are members of `s1` and not members of `s2`.

  See also:

  - union proc
  - intersection proc
  - symmetricDifference proc

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = difference(a, b)
      assert c == toHashSet(["a"])

  Source Edit

    proc disjoint[A](s1, s2: HashSet[A]): bool

  Returns `true` if the sets `s1` and `s2` have no items in common.

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
      assert disjoint(a, b) == false
      assert disjoint(a, b - a) == true

  Source Edit

    proc excl[A](s: var HashSet[A]; key: A)

  Excludes `key` from the set `s`.

  This doesn't do anything if `key` is not found in `s`.

  See also:

  - incl proc for including an element
  - excl proc for excluding other set
  - missingOrExcl proc

  Example:

      var s = toHashSet([2, 3, 6, 7])
      s.excl(2)
      s.excl(2)
      assert s.len == 3

  Source Edit

    proc excl[A](s: var HashSet[A]; other: HashSet[A])

  Excludes all elements of `other` set from `s`.

  This is the in-place version of s - other.

  See also:

  - incl proc for including other set
  - excl proc for excluding an element
  - missingOrExcl proc

  Example:

      var
        numbers = toHashSet([1, 2, 3, 4, 5])
        even = toHashSet([2, 4, 6, 8])
      numbers.excl(even)
      assert len(numbers) == 3
      ## numbers == {1, 3, 5}

  Source Edit

    proc excl[A](s: var OrderedSet[A]; key: A)

  Excludes `key` from the set `s`. Efficiency: `O(n)`.

  This doesn't do anything if `key` is not found in `s`.

  See also:

  - incl proc for including an element
  - missingOrExcl proc

  Example:

      var s = toOrderedSet([2, 3, 6, 7])
      s.excl(2)
      s.excl(2)
      assert s.len == 3

  Source Edit

    proc hash[A](s: HashSet[A]): Hash

  Hashing of HashSet. Source Edit

    proc hash[A](s: OrderedSet[A]): Hash

  Hashing of OrderedSet. Source Edit

    proc incl[A](s: var HashSet[A]; key: A)

  Includes an element `key` in `s`.

  This doesn't do anything if `key` is already in `s`.

  See also:

  - excl proc for excluding an element
  - incl proc for including other set
  - containsOrIncl proc

  Example:

      var values = initHashSet[int]()
      values.incl(2)
      values.incl(2)
      assert values.len == 1

  Source Edit

    proc incl[A](s: var HashSet[A]; other: HashSet[A])

  Includes all elements from `other` set into `s` (must be declared as `var`).

  This is the in-place version of s + other.

  See also:

  - excl proc for excluding other set
  - incl proc for including an element
  - containsOrIncl proc

  Example:

      var
        values = toHashSet([1, 2, 3])
        others = toHashSet([3, 4, 5])
      values.incl(others)
      assert values.len == 5

  Source Edit

    proc incl[A](s: var HashSet[A]; other: OrderedSet[A])

  Includes all elements from the OrderedSet `other` into HashSet `s` (must be declared as `var`).

  See also:

  - incl proc for including an element
  - containsOrIncl proc

  Example:

      var
        values = toHashSet([1, 2, 3])
        others = toOrderedSet([3, 4, 5])
      values.incl(others)
      assert values.len == 5

  Source Edit

    proc incl[A](s: var OrderedSet[A]; key: A)

  Includes an element `key` in `s`.

  This doesn't do anything if `key` is already in `s`.

  See also:

  - excl proc for excluding an element
  - incl proc for including other set
  - containsOrIncl proc

  Example:

      var values = initOrderedSet[int]()
      values.incl(2)
      values.incl(2)
      assert values.len == 1

  Source Edit

    proc init[A](s: var HashSet[A]; initialSize = defaultInitialSize)

  Initializes a hash set.

  Starting from Nim v0.20, sets are initialized by default and it is not necessary to call this function explicitly.

  You can call this proc on a previously initialized hash set, which will discard all its values. This might be more convenient than iterating over existing values and calling excl() on them.

  See also:

  - initHashSet proc
  - toHashSet proc

  Example:

      var a: HashSet[int]
      init(a)

  Source Edit

    proc init[A](s: var OrderedSet[A]; initialSize = defaultInitialSize)

  Initializes an ordered hash set.

  Starting from Nim v0.20, sets are initialized by default and it is not necessary to call this function explicitly.

  You can call this proc on a previously initialized hash set, which will discard all its values. This might be more convenient than iterating over existing values and calling excl() on them.

  See also:

  - initOrderedSet proc
  - toOrderedSet proc

  Example:

      var a: OrderedSet[int]
      init(a)

  Source Edit

    proc initHashSet[A](initialSize = defaultInitialSize): HashSet[A]

  Wrapper around init proc for initialization of hash sets.

  Returns an empty hash set you can assign directly in `var` blocks in a single line.

  Starting from Nim v0.20, sets are initialized by default and it is not necessary to call this function explicitly.

  See also:

  - toHashSet proc

  Example:

      var a = initHashSet[int]()
      a.incl(3)
      assert len(a) == 1

  Source Edit

    proc initOrderedSet[A](initialSize = defaultInitialSize): OrderedSet[A]

  Wrapper around init proc for initialization of ordered hash sets.

  Returns an empty ordered hash set you can assign directly in `var` blocks in a single line.

  Starting from Nim v0.20, sets are initialized by default and it is not necessary to call this function explicitly.

  See also:

  - toOrderedSet proc

  Example:

      var a = initOrderedSet[int]()
      a.incl(3)
      assert len(a) == 1

  Source Edit

    proc initSet[A](initialSize = defaultInitialSize): HashSet[A] {.
        ...deprecated: "Deprecated since v0.20, use \'initHashSet\'".}

  Deprecated: Deprecated since v0.20, use 'initHashSet'
  Source Edit

    proc intersection[A](s1, s2: HashSet[A]): HashSet[A]

  Returns the intersection of the sets `s1` and `s2`.

  The same as s1 * s2.

  The intersection of two sets is represented mathematically as A ∩ B and is the set of all objects that are members of `s1` and `s2` at the same time.

  See also:

  - union proc
  - difference proc
  - symmetricDifference proc

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = intersection(a, b)
      assert c == toHashSet(["b"])

  Source Edit

    proc isValid[A](s: HashSet[A]): bool {....deprecated: "Deprecated since v0.20; sets are initialized by default".}

  Deprecated: Deprecated since v0.20; sets are initialized by default
  Returns `true` if the set has been initialized (with initHashSet proc or init proc).

  Example:

      proc savePreferences(options: HashSet[string]) =
        assert options.isValid, "Pass an initialized set!"
        # Do stuff here, may crash in release builds!

  Source Edit

    proc len[A](s: HashSet[A]): int

  Returns the number of elements in `s`.

  Due to an implementation detail you can call this proc on variables which have not been initialized yet. The proc will return zero as the length then.

  Example:

      var a: HashSet[string]
      assert len(a) == 0
      let s = toHashSet([3, 5, 7])
      assert len(s) == 3

  Source Edit

    proc len[A](s: OrderedSet[A]): int {.inline.}

  Returns the number of elements in `s`.

  Due to an implementation detail you can call this proc on variables which have not been initialized yet. The proc will return zero as the length then.

  Example:

      var a: OrderedSet[string]
      assert len(a) == 0
      let s = toHashSet([3, 5, 7])
      assert len(s) == 3

  Source Edit

    proc map[A, B](data: HashSet[A]; op: proc (x: A): B {.closure.}): HashSet[B]

  Returns a new set after applying `op` proc on each of the elements of `data` set.

  You can use this proc to transform the elements from a set.

  Example:

      let
        a = toHashSet([1, 2, 3])
        b = a.map(proc (x: int): string = $x)
      assert b == toHashSet(["1", "2", "3"])

  Source Edit

    proc missingOrExcl[A](s: var HashSet[A]; key: A): bool

  Excludes `key` in the set `s` and tells if `key` was already missing from `s`.

  The difference with regards to the excl proc is that this proc returns `true` if `key` was missing from `s`. The proc will return `false` if `key` was in `s` and it was removed during this call.

  See also:

  - excl proc for excluding an element
  - excl proc for excluding other set
  - containsOrIncl proc

  Example:

      var s = toHashSet([2, 3, 6, 7])
      assert s.missingOrExcl(4) == true
      assert s.missingOrExcl(6) == false
      assert s.missingOrExcl(6) == true

  Source Edit

    proc missingOrExcl[A](s: var OrderedSet[A]; key: A): bool

  Excludes `key` in the set `s` and tells if `key` was already missing from `s`. Efficiency: O(n).

  The difference with regards to the excl proc is that this proc returns `true` if `key` was missing from `s`. The proc will return `false` if `key` was in `s` and it was removed during this call.

  See also:

  - excl proc
  - containsOrIncl proc

  Example:

      var s = toOrderedSet([2, 3, 6, 7])
      assert s.missingOrExcl(4) == true
      assert s.missingOrExcl(6) == false
      assert s.missingOrExcl(6) == true

  Source Edit

    proc pop[A](s: var HashSet[A]): A

  Removes and returns an arbitrary element from the set `s`.

  Raises KeyError if the set `s` is empty.

  See also:

  - clear proc

  Example:

      var s = toHashSet([2, 1])
      assert [s.pop, s.pop] in [[1, 2], [2,1]] # order unspecified
      doAssertRaises(KeyError, echo s.pop)

  Source Edit

    proc rightSize(count: Natural): int {.inline,
                                          ...deprecated: "Deprecated since 1.4.0",
                                          raises: [], tags: [].}

  Deprecated: Deprecated since 1.4.0

  It is not needed anymore because picking the correct size is done internally.

  Returns the value of `initialSize` to support `count` items.

  If more items are expected to be added, simply add that expected extra amount to the parameter before calling this.

  Source Edit

    proc symmetricDifference[A](s1, s2: HashSet[A]): HashSet[A]

  Returns the symmetric difference of the sets `s1` and `s2`.

  The same as s1 -+- s2.

  The symmetric difference of two sets is represented mathematically as A △ B or A ⊖ B and is the set of all objects that are members of `s1` or `s2` but not both at the same time.

  See also:

  - union proc
  - intersection proc
  - difference proc

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = symmetricDifference(a, b)
      assert c == toHashSet(["a", "c"])

  Source Edit

    proc toHashSet[A](keys: openArray[A]): HashSet[A]

  Creates a new hash set that contains the members of the given collection (seq, array, or string) `keys`.

  Duplicates are removed.

  See also:

  - initHashSet proc

  Example:

      let
        a = toHashSet([5, 3, 2])
        b = toHashSet("abracadabra")
      assert len(a) == 3
      ## a == {2, 3, 5}
      assert len(b) == 5
      ## b == {'a', 'b', 'c', 'd', 'r'}

  Source Edit

    proc toOrderedSet[A](keys: openArray[A]): OrderedSet[A]

  Creates a new hash set that contains the members of the given collection (seq, array, or string) `keys`.

  Duplicates are removed.

  See also:

  - initOrderedSet proc

  Example:

      let
        a = toOrderedSet([5, 3, 2])
        b = toOrderedSet("abracadabra")
      assert len(a) == 3
      ## a == {5, 3, 2} # different than in HashSet
      assert len(b) == 5
      ## b == {'a', 'b', 'r', 'c', 'd'} # different than in HashSet

  Source Edit

    proc toSet[A](keys: openArray[A]): HashSet[A] {.
        ...deprecated: "Deprecated since v0.20, use \'toHashSet\'".}

  Deprecated: Deprecated since v0.20, use 'toHashSet'
  Source Edit

    proc union[A](s1, s2: HashSet[A]): HashSet[A]

  Returns the union of the sets `s1` and `s2`.

  The same as s1 + s2.

  The union of two sets is represented mathematically as A ∪ B and is the set of all objects that are members of `s1`, `s2` or both.

  See also:

  - intersection proc
  - difference proc
  - symmetricDifference proc

  Example:

      let
        a = toHashSet(["a", "b"])
        b = toHashSet(["b", "c"])
        c = union(a, b)
      assert c == toHashSet(["a", "b", "c"])

  Source Edit

# Iterators

    iterator items[A](s: HashSet[A]): A

  Iterates over elements of the set `s`.

  If you need a sequence with the elements you can use sequtils.toSeq template.

      type
        pair = tuple[a, b: int]
      var
        a, b = initHashSet[pair]()
      a.incl((2, 3))
      a.incl((3, 2))
      a.incl((2, 3))
      for x, y in a.items:
        b.incl((x - 2, y + 1))
      assert a.len == 2
      echo b
      # --> {(a: 1, b: 3), (a: 0, b: 4)}

  Source Edit

    iterator items[A](s: OrderedSet[A]): A

  Iterates over keys in the ordered set `s` in insertion order.

  If you need a sequence with the elements you can use sequtils.toSeq template.

      var a = initOrderedSet[int]()
      for value in [9, 2, 1, 5, 1, 8, 4, 2]:
        a.incl(value)
      for value in a.items:
        echo "Got ", value
      # --> Got 9
      # --> Got 2
      # --> Got 1
      # --> Got 5
      # --> Got 8
      # --> Got 4

  Source Edit

    iterator pairs[A](s: OrderedSet[A]): tuple[a: int, b: A]

  Iterates through (position, value) tuples of OrderedSet `s`.

  Example:

      let a = toOrderedSet("abracadabra")
      var p = newSeq[(int, char)]()
      for x in pairs(a):
        p.add(x)
      assert p == @[(0, 'a'), (1, 'b'), (2, 'r'), (3, 'c'), (4, 'd')]

  Source Edit