JavaScript Basics: Compare Collections with Set Operations
Once you have unique values in sets, common collection questions become short operations: what belongs to either set, what belongs to both, and what is missing? Node.js 24 supports the Set composition methods used here. These operations produce new sets or boolean answers without changing the input sets.
These examples were tested on Linux with Node.js v24.19.0. They use built-in APIs only, need no network access, and include assertions that check the results. See the ECMAScript Set specification for the API contract.
Prepare a scratch directory
You need Bash, a text editor, Node.js 24 on your PATH, and the mktemp, rm, and rmdir utilities. Keep using the same terminal. The guarded commands stop the shell if setup fails. Save each named source file as UTF-8; .mjs selects ES modules.
node --version
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1The tested runtime prints:
v24.19.01. Combine labels and find shared labels
Save this as combine-label-sets.mjs:
import assert from 'node:assert/strict';
const first = new Set(['javascript', 'linux']);
const second = new Set(['linux', 'testing']);
const combined = first.union(second);
const shared = first.intersection(second);
assert.deepEqual([...combined], ['javascript', 'linux', 'testing']);
assert.deepEqual([...shared], ['linux']);
assert.deepEqual([...first], ['javascript', 'linux']);
console.log(`Either: ${[...combined].join(', ')}`);
console.log(`Both: ${[...shared].join(', ')}`);Run it:
node combine-label-sets.mjsOutput:
Either: javascript, linux, testing
Both: linuxUnion includes each distinct value found in either collection. Intersection includes only values present in both. The array spread makes the sets easy to display. Do not assume every set operation has the same ordering rule: intersection can choose iteration order based on the smaller input. Sort the resulting array explicitly when a presentation requires a particular order.
2. Find missing and changed selections
Save this as compare-selected-labels.mjs:
import assert from 'node:assert/strict';
const before = new Set(['draft', 'review']);
const after = new Set(['review', 'published']);
const removed = before.difference(after);
const added = after.difference(before);
const changed = before.symmetricDifference(after);
assert.deepEqual([...removed], ['draft']);
assert.deepEqual([...added], ['published']);
assert.deepEqual([...changed], ['draft', 'published']);
console.log(`Removed: ${[...removed].join(', ')}`);
console.log(`Added: ${[...added].join(', ')}`);
console.log(`Changed: ${[...changed].join(', ')}`);Run it:
node compare-selected-labels.mjsOutput:
Removed: draft
Added: published
Changed: draft, publishedDifference is directional: before.difference(after) is not the same question as after.difference(before). Symmetric difference includes values present in exactly one input, which is handy for spotting changed selections. These examples compare strings. Separate objects with identical fields still count as different values because Set membership compares object identity, not object contents.
3. Check requirements and conflicts
Save this as check-feature-requirements.mjs:
import assert from 'node:assert/strict';
const available = new Set(['read', 'write', 'export']);
const required = new Set(['read', 'export']);
const forbidden = new Set(['delete']);
assert.equal(required.isSubsetOf(available), true);
assert.equal(available.isSupersetOf(required), true);
assert.equal(available.isDisjointFrom(forbidden), true);
assert.equal(new Set(['delete']).isSubsetOf(available), false);
console.log(`Requirements met: ${required.isSubsetOf(available)}`);
console.log(`No conflicts: ${available.isDisjointFrom(forbidden)}`);Run it:
node check-feature-requirements.mjsOutput:
Requirements met: true
No conflicts: trueA subset check asks whether every required value is available. A disjointness check asks whether there are no shared values. These boolean results are useful for local validation and UI decisions; they are not a replacement for server-side authorization. Method availability differs in older runtimes, so run these examples on Node.js 24 rather than assuming every browser or older Node release supports them.
Clean up
In the same terminal, remove only the example files, return to your original directory, and remove the now-empty scratch directory:
rm -- combine-label-sets.mjs compare-selected-labels.mjs check-feature-requirements.mjs
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirAcknowledgements
This post was created with assistance from AI.