boop

Object-oriented programming for bash 4.3+ — real classes, objects, inheritance, and a standard library, in pure bash.


Project maintained by ydbxmhc Hosted on GitHub Pages

Collection.Set

Unordered collection of unique values. Backed by a bash associative array (keys are members, values are unused). Membership tests, add, and remove are O(1). Set operations (union, intersect, diffs, minus) return new Set objects.

Contents


Dependencies

. boop Set

Constructor

into=s Collection.Set

No arguments. You can seed it immediately:

into=s Collection.Set
$s.add "alpha" "beta" "gamma"

Membership

$s.add "foo"
$s.add "bar"

$s.has "foo" && echo "yes"    # exits 0
$s.has "baz" && echo "yes"    # exits 1 — silent

$s.add val [val...]

Add one or more members. Duplicates are silently ignored.

$s.add "x"
$s.add "x"         # no-op — already a member
$s.add "a" "b" "c" # add three at once

$s.has val

Exit code: 0 if val is a member, 1 if not.

if $s.has "$candidate"; then
  printf "%s is already registered\n" "$candidate"
fi

$s.remove val [val...]

Remove one or more members. No-op if any are absent.

$s.remove "foo"
$s.remove "a" "b" "c"   # remove several at once
$s.remove "missing"     # silent no-op

Size

into=n $s.size      # number of members
$s.isEmpty          # exit 0 if empty

Iteration

toArray returns all members joined by _EOL (default: newline). Iteration order is hash-defined — not insertion order.

_EOL=$'\n' into=members $s.toArray
while IFS= read -r m; do
  printf "member: %s\n" "$m"
done <<< "$members"

To get members as a bash array:

_EOL=$'\n' into=raw $s.toArray
mapfile -t arr <<< "$raw"
for m in "${arr[@]}"; do
  printf "%s\n" "$m"
done

Set Operations

All operations return a new Set object. The originals are unchanged.

a = {1, 2, 3}    b = {3, 4, 5}

union — all members of A or B

Symmetric: a.union(b) == b.union(a).

into=a Collection.Set; $a.add 1 2 3
into=b Collection.Set; $b.add 3 4 5

into=u $a.union "$b"
into=n $u.size          # "5"  → {1, 2, 3, 4, 5}

intersect — members in both A and B

Symmetric: a.intersect(b) == b.intersect(a).

into=i $a.intersect "$b"
into=n $i.size          # "1"  → {3}
$i.has "3" && echo "yes"

diffs — members in exactly one (symmetric difference)

Symmetric: a.diffs(b) == b.diffs(a).

into=d $a.diffs "$b"
into=n $d.size          # "4"  → {1, 2, 4, 5}
$d.has "1" && echo "only in a"
$d.has "5" && echo "only in b"

minus — members of A not in B (A − B)

Asymmetric: a.minus(b)b.minus(a).

into=m $a.minus "$b"
into=n $m.size          # "2"  → {1, 2}

into=m2 $b.minus "$a"
into=n $m2.size         # "2"  → {4, 5}

Common Patterns

Deduplication

into=seen Collection.Set
for item in "${items[@]}"; do
  if ! $seen.has "$item"; then
    $seen.add "$item"
    process "$item"
  fi
done

Tag/label system

into=tags Collection.Set
$tags.add "urgent" "backend" "v2"

$tags.has "urgent" && notify_oncall

Computing changed items

into=old Collection.Set
into=new Collection.Set
# ... populate both ...

into=added   $new.minus    "$old"    # in new but not old
into=removed $old.minus    "$new"    # in old but not new
into=changed $old.diffs    "$new"    # in exactly one (added or removed)
into=kept    $old.intersect "$new"   # in both

Design Notes

O(1) membership. has looks up a key in a bash associative array — one operation, no iteration.

Unordered. Bash associative arrays have hash-defined iteration order. If you need a set with stable iteration order, use a Map (insert key with a placeholder value; $map.keys gives insertion order).

Values are strings. Set members can be any string, including object IDs, file paths, or multi-word strings.


↑ Site map