Expand/Shrink

sets.e

The file builtins/sets.e (not an autoinclude) contains routines for simple handling of sets.

Aside: For no particularly good reason I launched a full-on rewrite, which has ended up in builtins/sets2.e - and was not in the end proved any better or worse, however I realised set-ids just make debugging harder, I think...

Internally these routines use a private set_type, but that is documented as sequence here since that is what an application should use.

These routines all work just fine under pwa/p2js, aka "with js", although deep_copy() may be required when result!=s1.

bool result = 
is_empty(sequence s1) -- returns true if s1 is empty

Symbolically represented with a circle with a diagonal through it: ∅

bool result = 
is_member(sequence s1, object x) -- returns true if x is a member of s1

Symbolically represented with an E shape: ∈

sequence result = 
add_member(sequence s1, object x) -- returns s1 with x added if it was not already present

sequence result = 
remove_member(sequence s1, object x) -- returns s1 with x removed if it was present

sequence result = 
union(sequence s1, object s2=-1)

Returns anything that occurs in any set.
Symbolically represented with a U shape: ∪
Can be invoked as union(s1,s2) or union({s1,s2}), where s1 and s2 are sequences and the second form permits more than two/any number of sets.
The union of empty sets is the empty set, as is the union of an empty set of sets. Otherwise empty sets have no impact on the result when in the presence of other non-empty sets.
An error ocurs when s1 or s2 or elements within that should be sequences/sets are in fact atoms.
While s1 can be a set of sets, an error occurs if at the same time s2 is a set or set of sets.
Strings (char sets) are perfectly fine too.

sequence result = 
intersection(sequence s1, object s2=-1)

Returns anything that occurs in every set.
Symbolically represented as upsidedown U: ∩
Can be invoked as intersection(s1,s2) or as intersection({s1,s2}), where s1 and s2 are sequences and the second form permits more than two/any number of sets.
The intersection of empty sets is the empty set, as is the intersection of an empty set of sets, or a set of just one set.
The presence of any empty set means that the result will also be the empty set.
An error ocurs when s1 or s2 or elements within that should be sequences/sets are in fact atoms.
While s1 can be a set of sets, an error occurs if at the same time s2 is a set or set of sets.
Strings (char sets) are perfectly fine too.

sequence result = 
difference(sequence s1, object s2=-1, bool symmetric=true)

Returns anything missing from some other set.
If symmetric is false only items from s1 or s1[1] are returned, otherwise the result contains each and every item in any set that is missing from any of the other sets.
Obviously difference(s1,s2,true) is effectively the same as union(difference(s1,s2,false),difference(s2,s1,false))
[slightly more complicated than that when s1 is a set of sets, but you should get the idea]
Symbolically represented as:
symmetric: a triangle, or sometimes as a circle with a horizontal line,
relative: a backslash

bool result = 
is_subset(sequence subset, superset) -- returns false if any element of subset is not in superset

Symbolically represented as: ⊂

bool result = 
is_superset(sequence superset, subset) -- returns true if all elements of subset are in superset

Symbolically represented as: ⊃