#Set Package Documentation

    This package provides a hash-based set data structure that maintains insertion order. The Set[K] type stores unique elements and provides efficient membership testing, insertion, and deletion operations.

    #Creating Sets

    There are several ways to create sets:

    ///|
    test "creating sets" {
    // Empty set
    let empty_set : @set.Set[Int] = Set([])
    inspect(empty_set.length(), content="0")
    inspect(empty_set.is_empty(), content="true")

    // Set with initial capacity
    let set_with_capacity : @set.Set[Int] = Set([], capacity=16)
    inspect(set_with_capacity.capacity(), content="16")

    // From array
    let from_array = @set.Set([1, 2, 3, 2, 1]) // Duplicates are removed
    inspect(from_array.length(), content="3")

    // From an array literal
    let from_fixed = @set.Set([10, 20, 30])
    inspect(from_fixed.length(), content="3")

    // From iterator
    let from_iter = @set.Set::from_iter(1, 2, 3, 4, 5)
    inspect(from_iter.length(), content="5")
    }

    #Basic Operations

    Add, remove, and check membership:

    ///|
    test "basic operations" {
    let set = @set.Set([])

    // Adding elements
    set.add("apple")
    set.add("banana")
    set.add("cherry")
    inspect(set.length(), content="3")

    // Adding duplicate (no effect)
    set.add("apple")
    inspect(set.length(), content="3") // Still 3

    // Check membership
    inspect(set.contains("apple"), content="true")
    inspect(set.contains("orange"), content="false")

    // Remove elements
    set.remove("banana")
    inspect(set.contains("banana"), content="false")
    inspect(set.length(), content="2")

    // Check if addition/removal was successful
    let was_added = set.add_and_check("date")
    inspect(was_added, content="true")
    let was_added_again = set.add_and_check("date")
    inspect(was_added_again, content="false") // Already exists
    let was_removed = set.remove_and_check("cherry")
    inspect(was_removed, content="true")
    let was_removed_again = set.remove_and_check("cherry")
    inspect(was_removed_again, content="false") // Doesn't exist
    }

    #Set Operations

    Perform mathematical set operations:

    ///|
    test "set operations" {
    let set1 = @set.Set([1, 2, 3, 4])
    let set2 = @set.Set([3, 4, 5, 6])

    // Union (all elements from both sets)
    let union_set = set1.union(set2)
    let union_array = union_set.to_array()
    inspect(union_array.length(), content="6") // [1, 2, 3, 4, 5, 6]

    // Alternative union syntax
    let union_alt = set1 | set2
    inspect(union_alt.length(), content="6")

    // Intersection (common elements)
    let intersection_set = set1.intersection(set2)
    let intersection_array = intersection_set.to_array()
    inspect(intersection_array.length(), content="2") // [3, 4]

    // Alternative intersection syntax
    let intersection_alt = set1 & set2
    inspect(intersection_alt.length(), content="2")

    // Difference (elements in first but not second)
    let difference_set = set1.difference(set2)
    let difference_array = difference_set.to_array()
    inspect(difference_array.length(), content="2") // [1, 2]

    // Alternative difference syntax
    let difference_alt = set1 - set2
    inspect(difference_alt.length(), content="2")

    // Symmetric difference (elements in either but not both)
    let sym_diff_set = set1.symmetric_difference(set2)
    let sym_diff_array = sym_diff_set.to_array()
    inspect(sym_diff_array.length(), content="4") // [1, 2, 5, 6]

    // Alternative symmetric difference syntax
    let sym_diff_alt = set1 ^ set2
    inspect(sym_diff_alt.length(), content="4")
    }

    #Set Relationships

    Test relationships between sets:

    ///|
    test "set relationships" {
    let small_set = @set.Set([1, 2])
    let large_set = @set.Set([1, 2, 3, 4])
    let disjoint_set = @set.Set([5, 6, 7])

    // Subset testing
    inspect(small_set.is_subset(large_set), content="true")
    inspect(large_set.is_subset(small_set), content="false")

    // Superset testing
    inspect(large_set.is_superset(small_set), content="true")
    inspect(small_set.is_superset(large_set), content="false")

    // Disjoint testing (no common elements)
    inspect(small_set.is_disjoint(disjoint_set), content="true")
    inspect(small_set.is_disjoint(large_set), content="false")

    // Equal sets
    let set1 = @set.Set([1, 2, 3])
    let set2 = @set.Set([3, 2, 1]) // Order doesn't matter
    inspect(set1 == set2, content="true")
    }

    #Iteration and Conversion

    Iterate over sets and convert to other types:

    ///|
    test "iteration and conversion" {
    let set = @set.Set(["first", "second", "third"])

    // Convert to array (maintains insertion order)
    let array = set.to_array()
    inspect(array.length(), content="3")

    // Iterate over elements
    let mut count = 0
    set.each(fn(_element) { count = count + 1 })
    inspect(count, content="3")

    // Iterate with index
    let mut indices_sum = 0
    set.eachi(fn(i, _element) { indices_sum = indices_sum + i })
    inspect(indices_sum, content="3") // 0 + 1 + 2 = 3

    // Use iterator
    let elements = set.iter().collect()
    inspect(elements.length(), content="3")

    // Copy a set
    let copied_set = set.copy()
    inspect(copied_set.length(), content="3")
    inspect(copied_set == set, content="true")
    }

    #Modifying Sets

    Clear and modify existing sets:

    ///|
    test "modifying sets" {
    let set = @set.Set([10, 20, 30, 40, 50])
    inspect(set.length(), content="5")

    // Clear all elements
    set.clear()
    inspect(set.length(), content="0")
    inspect(set.is_empty(), content="true")

    // Add elements back
    set.add(100)
    set.add(200)
    inspect(set.length(), content="2")
    inspect(set.contains(100), content="true")
    }

    #JSON Serialization

    Sets can be serialized to JSON as arrays:

    ///|
    test "json serialization" {
    let set = @set.Set([1, 2, 3])
    let json = @json.to_json(set)

    // JSON representation is an array
    @debug.debug_inspect(json, content="Array([Number(1), Number(2), Number(3)])")

    // String set
    let string_set = @set.Set(["a", "b", "c"])
    let string_json = @json.to_json(string_set)
    @debug.debug_inspect(
    string_json,
    content="Array([String(\"a\"), String(\"b\"), String(\"c\")])",
    )
    }

    #Working with Different Types

    Sets work with any type that implements Hash and Eq:

    ///|
    test "different types" {
    // Integer set
    let int_set = @set.Set([1, 2, 3, 4, 5])
    inspect(int_set.contains(3), content="true")

    // String set
    let string_set = @set.Set(["hello", "world", "moonbit"])
    inspect(string_set.contains("world"), content="true")

    // Char and Bool implement Hash too, so they work as element types as well
    // Here we use Int codes just for demonstration
    let char_codes = @set.Set([97, 98, 99]) // ASCII codes for 'a', 'b', 'c'
    inspect(char_codes.contains(98), content="true") // 'b' = 98

    // Integer set representing boolean values
    let bool_codes = @set.Set([1, 0, 1]) // 1=true, 0=false
    inspect(bool_codes.length(), content="2") // Only 1 and 0
    }

    #Performance Examples

    Demonstrate efficient operations:

    ///|
    test "performance examples" {
    // Large set operations
    let large_set = @set.Set([], capacity=1000)

    // Add many elements
    for i in 0..<100 {
    large_set.add(i)
    }
    inspect(large_set.length(), content="100")

    // Fast membership testing
    inspect(large_set.contains(50), content="true")
    inspect(large_set.contains(150), content="false")

    // Efficient set operations on large sets
    let another_set = @set.Set([])
    for i in 50..<150 {
    another_set.add(i)
    }
    let intersection = large_set.intersection(another_set)
    inspect(intersection.length(), content="50") // Elements 50-99
    }

    #Use Cases

    Sets are particularly useful for:

    1. Removing duplicates: Convert arrays to sets and back to remove duplicates
    2. Membership testing: Fast O(1) average-case lookups
    3. Mathematical operations: Union, intersection, difference operations
    4. Unique collections: Maintaining collections of unique items
    5. Algorithm implementation: Graph algorithms, caching, etc.

    #Performance Characteristics

    • Insertion: O(1) average case, O(n) worst case
    • Removal: O(1) average case, O(n) worst case
    • Lookup: O(1) average case, O(n) worst case
    • Space complexity: O(n) where n is the number of elements
    • Iteration order: Maintains insertion order (linked hash set)

    #Best Practices

    1. Pre-size when possible: Use @set.Set([], capacity=n) if you know the approximate size
    2. Use appropriate types: Ensure your key type has good Hash and Eq implementations
    3. Prefer set operations: Use built-in union, intersection, etc. instead of manual loops
    4. Check return values: Use add_and_check and remove_and_check when you need to know if the operation succeeded
    5. Consider memory usage: Sets have overhead compared to arrays for small collections

    Set

    type Set[K]

    Mutable linked hash set that maintains the order of insertion, not thread safe.

    Example

    test {
    let set = @set.Set(["three", "eight", "one"])
    @test.assert_eq(set.contains("two"), false)
    @test.assert_eq(set.contains("three"), true)
    set.add("three") // no effect since it already exists
    set.add("two")
    @test.assert_eq(set.contains("two"), true)
    }
    impl BitAnd for Set[K]
    impl BitOr for Set[K]
    impl BitXOr for Set[K]
    impl Default for Set[K]
    impl Eq for Set[K]
    impl Sub for Set[K]
    impl ToJson for Set[X]

    Set::Set

    #as_free_fn(of, deprecated="Use from_array instead")
    #alias(of, deprecated="Use from_array instead")
    #as_free_fn(from_array)
    #alias(from_array)
    fn[K : Hash + Eq] Set::Set(arr : ArrayView[K], capacity? : Int) -> Set[K]

    Creates a hash set containing all elements from the given array, preserving insertion order. The optional capacity is treated as a minimum initial capacity and will be rounded up to the smallest power of 2 that can hold the requested capacity.

    Set::add

    #alias(insert, deprecated="`insert` is deprecated, use `add` instead")
    fn[K : Hash + Eq] Set::add(self : Set[K], key : K) -> Unit

    Insert a key into the hash set.

    Parameters:

    • set : The hash set to modify.
    • key : The key to insert. Must implement Hash and Eq traits.

    Example:

    test {
    let set : @set.Set[String] = Set([])
    set.add("key")
    inspect(set.contains("key"), content="true")
    set.add("key") // no effect since it already exists
    inspect(set.length(), content="1")
    }

    Set::add_and_check

    fn[K : Hash + Eq] Set::add_and_check(self : Set[K], key : K) -> Bool

    Insert a key into the hash set and returns whether the key was successfully added.

    Parameters:

    • set : The hash set to modify.
    • key : The key to insert. Must implement Hash and Eq traits.

    Returns true if the key was successfully added (i.e., it wasn't already present), false if the key already existed in the set.

    Example:

    test {
    let set : @set.Set[String] = Set([])
    inspect(set.add_and_check("key"), content="true") // First insertion
    inspect(set.add_and_check("key"), content="false") // Already exists
    inspect(set.length(), content="1")
    }

    Set::capacity

    fn[K] Set::capacity(self : Set[K]) -> Int

    Get the capacity of the set.

    Set::clear

    fn[K] Set::clear(self : Set[K]) -> Unit

    Clears the set, removing all keys. Keeps the allocated space.

    Set::contains

    fn[K : Hash + Eq] Set::contains(self : Set[K], key : K) -> Bool

    Check if the hash set contains a key.

    Set::copy

    #alias(clone, deprecated="`clone` is deprecated, use `copy` instead")
    fn[K] Set::copy(self : Set[K]) -> Set[K]

    Copy the set, creating a new set with the same keys and order of insertion.

    Set::difference

    fn[K : Hash + Eq] Set::difference(self : Set[K], other : Set[K]) -> Set[K]

    Returns a new set containing elements in self that are not in other.

    Set::each

    fn[K] Set::each(self : Set[K], f : (K) -> Unit raise?) -> Unit raise?

    Iterate over all keys of the set in the order of insertion.

    Set::eachi

    fn[K] Set::eachi(self : Set[K], f : (Int, K) -> Unit raise?) -> Unit raise?

    Iterate over all keys of the set in the order of insertion, with index.

    Set::equal

    fn[K : Hash + Eq] Set::equal(self : Set[K], other : Set[K]) -> Bool

    Set::from_iter

    #as_free_fn(from_iterator, deprecated="Use Set::from_iter instead.")
    #alias(from_iterator, deprecated="`from_iterator` is deprecated, use `from_iter` instead")
    #as_free_fn
    fn[K : Hash + Eq] Set::from_iter(iter : Iter[K]) -> Set[K]

    Create from iter.

    Set::intersection

    fn[K : Hash + Eq] Set::intersection(self : Set[K], other : Set[K]) -> Set[K]

    Returns a new set containing only elements present in both sets.

    Set::is_disjoint

    fn[K : Hash + Eq] Set::is_disjoint(self : Set[K], other : Set[K]) -> Bool

    Returns true if the two sets have no elements in common.

    Set::is_empty

    fn[K] Set::is_empty(self : Set[K]) -> Bool

    Check if the hash set is empty.

    Set::is_subset

    fn[K : Hash + Eq] Set::is_subset(self : Set[K], other : Set[K]) -> Bool

    Returns true if every element of self is also in other.

    Set::is_superset

    fn[K : Hash + Eq] Set::is_superset(self : Set[K], other : Set[K]) -> Bool

    Returns true if every element of other is also in self.

    Set::iter

    #alias(iterator, deprecated="`iterator` is deprecated, use `iter` instead")
    fn[K] Set::iter(self : Set[K]) -> Iter[K]

    Returns the iterator of the hash set, provide elements in the order of insertion.

    Set::land

    fn[K : Hash + Eq] Set::land(self : Set[K], other : Set[K]) -> Set[K]

    Set::length

    #alias(size, deprecated="`size` is deprecated, use `length` instead")
    fn[K] Set::length(self : Set[K]) -> Int

    Get the number of keys in the set.

    Set::lor

    fn[K : Hash + Eq] Set::lor(self : Set[K], other : Set[K]) -> Set[K]

    Set::lxor

    fn[K : Hash + Eq] Set::lxor(self : Set[K], other : Set[K]) -> Set[K]

    Set::new

    #as_free_fn(deprecated="Use `Set([], capacity=...)` instead")
    #deprecated("Use `Set([], capacity=...)` instead")
    fn[K] Set::new(capacity? : Int) -> Set[K]

    Creates an empty insertion-ordered hash set with an optional initial capacity.

    Deprecated: use Set([], capacity=...) instead.

    Set::remove

    fn[K : Hash + Eq] Set::remove(self : Set[K], key : K) -> Unit

    Remove a key from the hash set. If the key exists in the set, removes it and adjusts the probe sequence length (PSL) of subsequent entries to maintain the Robin Hood hashing invariant. If the key does not exist, the set remains unchanged.

    Parameters:

    • self : The hash set to remove the key from.
    • key : The key to remove from the set.

    Example:

    test {
    let set = @set.Set(["a", "b"])
    set.remove("a")
    inspect(set.contains("a"), content="false")
    inspect(set.length(), content="1")
    }

    Set::remove_and_check

    fn[K : Hash + Eq] Set::remove_and_check(self : Set[K], key : K) -> Bool

    Remove a key from the hash set and returns whether the key was successfully removed.

    Parameters:

    • set : The hash set to modify.
    • key : The key to remove. Must implement Hash and Eq traits.

    Returns true if the key was successfully removed (i.e., it was present), false if the key didn't exist in the set.

    Example:

    test {
    let set = @set.Set(["a", "b"])
    inspect(set.remove_and_check("a"), content="true") // Successfully removed
    inspect(set.remove_and_check("a"), content="false") // Already removed
    inspect(set.length(), content="1")
    }

    Set::sub

    fn[K : Hash + Eq] Set::sub(self : Set[K], other : Set[K]) -> Set[K]

    Set::symmetric_difference

    fn[K : Hash + Eq] Set::symmetric_difference(self : Set[K], other : Set[K]) -> Set[K]

    Returns a new set containing elements in exactly one of the two sets.

    Set::to_array

    fn[K] Set::to_array(self : Set[K]) -> Array[K]

    Converts the hash set to an array.

    Set::union

    fn[K : Hash + Eq] Set::union(self : Set[K], other : Set[K]) -> Set[K]

    Returns a new set containing all elements from both sets.