An ordered set backed by a B-tree of order 5.
Elements are kept in ascending Erlang term order, and each value appears at most once.
Comparisons use == rather than === — so 1 and 1.0 are treated as the same
element, unlike MapSet.
Conversion to a list via to_list/1 always yields elements in ascending
order.
Erlang interop
Xb5.Set is compatible with the Erlang :xb5_sets module. Build one from an
:xb5_sets term via new/1. To go the other way, call unwrap!/1 to extract the
size and root node, then pass the result to :xb5_sets.wrap/1.
See also
Xb5.Bag— ordered multiset with order-statistic operations (percentile, rank)Xb5.Tree— ordered key-value store.
Examples
iex> set = Xb5.Set.new([3, 1, 2, 1])
Xb5.Set.new([1, 2, 3])
iex> Xb5.Set.member?(set, 2)
true
iex> Xb5.Set.last!(set)
3
Summary
Functions
Deletes value from set.
Returns a set that is set1 without the members of set2.
Checks if set1 and set2 have no members in common.
Checks if two sets are equal.
Filters set by returning only elements for which fun returns a truthy value.
Returns the first (smallest) element in set, or default if set is empty.
Returns the first (smallest) element in set.
Returns the smallest element in set strictly greater (larger) than value,
or :error if none exists.
Returns a set containing only members that set1 and set2 have in common.
Returns the last (largest) element in set, or default if set is empty.
Returns the last (largest) element in set.
Returns the largest element in set strictly less (smaller) than value, or
:error if none exists.
Applies fun to each element and returns a new set built from the results.
Checks if set contains value.
Returns a new empty set.
Creates a set from an Erlang :xb5_sets term or an enumerable.
Creates a set from an Erlang :xb5_sets term or an enumerable via the transformation function.
Removes and returns {value, updated_set} for the first (smallest) element in set.
Removes and returns {value, updated_set} for the last (largest) element in set.
Inserts value into set if set doesn't already contain it.
Returns a set by excluding the elements from set for which fun returns a truthy value.
Returns the number of elements in set.
Splits set into two sets according to the given function fun.
Returns a lazy stream over all elements of set.
Returns a lazy stream over elements of set starting from value.
Returns structural statistics about the underlying B-tree.
Checks if set1's members are all contained in set2.
Returns a set with elements that are present in only one but not both sets.
Converts set to a sorted list.
Returns a set containing all members of set1 and set2.
Returns the size and root node of set as %{size: n, root: node}.
Types
@type order() :: :asc | :desc
@type t(value) :: %Xb5.Set{root: :xb5_sets_node.t(value), size: non_neg_integer()}
@type value() :: term()
Functions
Deletes value from set.
Returns a new set which is a copy of set but without value.
Examples
iex> set = Xb5.Set.new([1, 2, 3])
iex> Xb5.Set.delete(set, 4)
Xb5.Set.new([1, 2, 3])
iex> Xb5.Set.delete(set, 2)
Xb5.Set.new([1, 3])
Returns a set that is set1 without the members of set2.
Examples
iex> Xb5.Set.difference(Xb5.Set.new([1, 2]), Xb5.Set.new([2, 3, 4]))
Xb5.Set.new([1])
Checks if set1 and set2 have no members in common.
Examples
iex> Xb5.Set.disjoint?(Xb5.Set.new([1, 2]), Xb5.Set.new([3, 4]))
true
iex> Xb5.Set.disjoint?(Xb5.Set.new([1, 2]), Xb5.Set.new([2, 3]))
false
Checks if two sets are equal.
The comparison between elements is done using ==, so for example
Xb5.Set.new([1]) is equal to Xb5.Set.new([1.0]).
Examples
iex> Xb5.Set.equal?(Xb5.Set.new([1, 2]), Xb5.Set.new([2, 1, 1]))
true
iex> Xb5.Set.equal?(Xb5.Set.new([1, 2]), Xb5.Set.new([3, 4]))
false
iex> Xb5.Set.equal?(Xb5.Set.new([1]), Xb5.Set.new([1.0]))
true
@spec filter(t(a), (a -> as_boolean(term()))) :: t(a) when a: value()
Filters set by returning only elements for which fun returns a truthy value.
Also see reject/2 which discards all elements where the function returns
a truthy value.
Examples
iex> Xb5.Set.filter(Xb5.Set.new(1..5), fn x -> x > 3 end)
Xb5.Set.new([4, 5])
iex> Xb5.Set.filter(Xb5.Set.new(["a", :b, "c"]), &is_atom/1)
Xb5.Set.new([:b])
Returns the first (smallest) element in set, or default if set is empty.
Examples
iex> Xb5.Set.first(Xb5.Set.new([1, 2, 3]))
1
iex> Xb5.Set.first(Xb5.Set.new())
nil
iex> Xb5.Set.first(Xb5.Set.new(), :empty)
:empty
Returns the first (smallest) element in set.
Raises Xb5.EmptyError if set is empty.
Examples
iex> Xb5.Set.first!(Xb5.Set.new([1, 2, 3]))
1
iex> Xb5.Set.first!(Xb5.Set.new())
** (Xb5.EmptyError) empty error
Returns the smallest element in set strictly greater (larger) than value,
or :error if none exists.
value does not need to be a member of set.
Examples
iex> Xb5.Set.higher(Xb5.Set.new([1, 2, 3]), 2)
{:ok, 3}
iex> Xb5.Set.higher(Xb5.Set.new([1, 2, 3]), 1.5)
{:ok, 2}
iex> Xb5.Set.higher(Xb5.Set.new([1, 2, 3]), 3)
:error
Returns a set containing only members that set1 and set2 have in common.
Examples
iex> Xb5.Set.intersection(Xb5.Set.new([1, 2]), Xb5.Set.new([2, 3, 4]))
Xb5.Set.new([2])
iex> Xb5.Set.intersection(Xb5.Set.new([1, 2]), Xb5.Set.new([3, 4]))
Xb5.Set.new([])
Returns the last (largest) element in set, or default if set is empty.
Examples
iex> Xb5.Set.last(Xb5.Set.new([1, 2, 3]))
3
iex> Xb5.Set.last(Xb5.Set.new())
nil
iex> Xb5.Set.last(Xb5.Set.new(), :empty)
:empty
Returns the last (largest) element in set.
Raises Xb5.EmptyError if set is empty.
Examples
iex> Xb5.Set.last!(Xb5.Set.new([1, 2, 3]))
3
iex> Xb5.Set.last!(Xb5.Set.new())
** (Xb5.EmptyError) empty error
Returns the largest element in set strictly less (smaller) than value, or
:error if none exists.
value does not need to be a member of set.
Examples
iex> Xb5.Set.lower(Xb5.Set.new([1, 2, 3]), 2)
{:ok, 1}
iex> Xb5.Set.lower(Xb5.Set.new([1, 2, 3]), 1.5)
{:ok, 1}
iex> Xb5.Set.lower(Xb5.Set.new([1, 2, 3]), 1)
:error
Applies fun to each element and returns a new set built from the results.
Because the mapped elements may not be unique, they are deduplicated.
Examples
iex> Xb5.Set.map(Xb5.Set.new([1, 2, 3]), fn x -> x * 2 end)
Xb5.Set.new([2, 4, 6])
iex> Xb5.Set.map(Xb5.Set.new([1, 2, 3]), fn _ -> :same end)
Xb5.Set.new([:same])
Checks if set contains value.
Membership is tested using ==, not ===, so for example member?(set, 1.0) will
match an element 1.
Examples
iex> Xb5.Set.member?(Xb5.Set.new([1, 2, 3]), 2)
true
iex> Xb5.Set.member?(Xb5.Set.new([1, 2, 3]), 4)
false
@spec new() :: t()
Returns a new empty set.
Examples
iex> Xb5.Set.new()
Xb5.Set.new([])
@spec new(:xb5_sets.set(value()) | Enumerable.t()) :: t(value())
Creates a set from an Erlang :xb5_sets term or an enumerable.
When given an enumerable, elements are deduplicated and stored in ascending order.
When given an Erlang :xb5_sets term, the underlying structure is reused directly.
Examples
iex> Xb5.Set.new([:b, :a, 3])
Xb5.Set.new([3, :a, :b])
iex> Xb5.Set.new([3, 3, 3, 2, 2, 1])
Xb5.Set.new([1, 2, 3])
@spec new(:xb5_sets.set() | Enumerable.t(), (term() -> value())) :: t(value())
Creates a set from an Erlang :xb5_sets term or an enumerable via the transformation function.
The results of transform are deduplicated and stored in ascending order.
Examples
iex> Xb5.Set.new([1, 2, 1], fn x -> 2 * x end)
Xb5.Set.new([2, 4])
Removes and returns {value, updated_set} for the first (smallest) element in set.
Raises Xb5.EmptyError if set is empty.
Examples
iex> Xb5.Set.pop_first!(Xb5.Set.new([1, 2, 3]))
{1, Xb5.Set.new([2, 3])}
iex> Xb5.Set.pop_first!(Xb5.Set.new())
** (Xb5.EmptyError) empty error
Removes and returns {value, updated_set} for the last (largest) element in set.
Raises Xb5.EmptyError if set is empty.
Examples
iex> Xb5.Set.pop_last!(Xb5.Set.new([1, 2, 3]))
{3, Xb5.Set.new([1, 2])}
iex> Xb5.Set.pop_last!(Xb5.Set.new())
** (Xb5.EmptyError) empty error
Inserts value into set if set doesn't already contain it.
Examples
iex> Xb5.Set.put(Xb5.Set.new([1, 2, 3]), 3)
Xb5.Set.new([1, 2, 3])
iex> Xb5.Set.put(Xb5.Set.new([1, 2, 3]), 4)
Xb5.Set.new([1, 2, 3, 4])
@spec reject(t(a), (a -> as_boolean(term()))) :: t(a) when a: value()
Returns a set by excluding the elements from set for which fun returns a truthy value.
See also filter/2.
Examples
iex> Xb5.Set.reject(Xb5.Set.new(1..5), fn x -> rem(x, 2) != 0 end)
Xb5.Set.new([2, 4])
iex> Xb5.Set.reject(Xb5.Set.new(["a", :b, "c"]), &is_atom/1)
Xb5.Set.new(["a", "c"])
@spec size(t()) :: non_neg_integer()
Returns the number of elements in set.
Examples
iex> Xb5.Set.size(Xb5.Set.new([1, 2, 3]))
3
Splits set into two sets according to the given function fun.
Returns a tuple with the first set containing all elements for which fun returned
a truthy value, and a second set with all elements for which fun returned a falsy
value (false or nil).
Examples
iex> {while_true, while_false} = Xb5.Set.split_with(Xb5.Set.new([1, 2, 3, 4]), fn v -> rem(v, 2) == 0 end)
iex> while_true
Xb5.Set.new([2, 4])
iex> while_false
Xb5.Set.new([1, 3])
iex> {while_true, while_false} = Xb5.Set.split_with(Xb5.Set.new(), fn v -> v > 50 end)
iex> while_true
Xb5.Set.new([])
iex> while_false
Xb5.Set.new([])
@spec stream(t(value()), order()) :: Enumerable.t()
Returns a lazy stream over all elements of set.
order controls traversal direction: :asc (ascending, the default) or
:desc (descending).
Examples
iex> set = Xb5.Set.new([1, 2, 3])
iex> Xb5.Set.stream(set) |> Enum.to_list()
[1, 2, 3]
iex> Xb5.Set.stream(set, :desc) |> Enum.to_list()
[3, 2, 1]
iex> Xb5.Set.stream(Xb5.Set.new()) |> Enum.to_list()
[]
@spec stream_from(t(value()), value(), order()) :: Enumerable.t()
Returns a lazy stream over elements of set starting from value.
For :asc (the default), starts at the first element greater than or
equal to value. For :desc, starts at the first element less than or
equal to value. Returns an empty stream if no such element exists.
Examples
iex> set = Xb5.Set.new([1, 2, 3, 4, 5])
iex> Xb5.Set.stream_from(set, 3) |> Enum.to_list()
[3, 4, 5]
iex> Xb5.Set.stream_from(set, 3, :desc) |> Enum.to_list()
[3, 2, 1]
iex> Xb5.Set.stream_from(set, 6) |> Enum.to_list()
[]
@spec structural_stats(t()) :: :xb5_structural_stats.t()
Returns structural statistics about the underlying B-tree.
Useful for inspecting tree balance and node utilization.
Examples
iex> Xb5.Set.structural_stats(Xb5.Set.new(1..100))
[
height: 4,
node_counts: [
internal4: 2,
internal3: 3,
internal2: 3,
internal1: 1,
leaf4: 6,
leaf3: 14,
leaf2: 5,
leaf1: 0
],
node_percentages: [
internal4: 5.9,
internal3: 8.8,
internal2: 8.8,
internal1: 2.9,
leaf4: 17.6,
leaf3: 41.2,
leaf2: 14.7,
leaf1: 0.0
],
total_keys: 100,
key_percentages: [
internal4: 8.0,
internal3: 9.0,
internal2: 6.0,
internal1: 1.0,
leaf4: 24.0,
leaf3: 42.0,
leaf2: 10.0,
leaf1: 0.0
],
avg_keys_per_node: 2.9411764705882355,
avg_keys_per_internal_node: 2.6666666666666665,
avg_keys_per_leaf_node: 3.04
]
Checks if set1's members are all contained in set2.
This function checks if set1 is a subset of set2.
Examples
iex> Xb5.Set.subset?(Xb5.Set.new([1, 2]), Xb5.Set.new([1, 2, 3]))
true
iex> Xb5.Set.subset?(Xb5.Set.new([1, 2, 3]), Xb5.Set.new([1, 2]))
false
Returns a set with elements that are present in only one but not both sets.
Implemented as union(difference(set1, set2), difference(set2, set1)).
Examples
iex> Xb5.Set.symmetric_difference(Xb5.Set.new([1, 2, 3]), Xb5.Set.new([2, 3, 4]))
Xb5.Set.new([1, 4])
Converts set to a sorted list.
Examples
iex> Xb5.Set.to_list(Xb5.Set.new([1, 2, 3]))
[1, 2, 3]
Returns a set containing all members of set1 and set2.
Examples
iex> Xb5.Set.union(Xb5.Set.new([1, 2]), Xb5.Set.new([2, 3, 4]))
Xb5.Set.new([1, 2, 3, 4])
@spec unwrap!(t(value())) :: :xb5_sets.unwrapped_set(value())
Returns the size and root node of set as %{size: n, root: node}.
Pass the result to :xb5_sets.wrap/1 to obtain a proper :xb5_sets term.
Examples
iex> %{size: size} = Xb5.Set.unwrap!(Xb5.Set.new([1, 2, 3]))
iex> size
3