Skip to content

@absoluteui/helpers/set

Union, intersection, difference, and relations for arrays and Sets, with key selectors.

import { ... } from '@absoluteui/helpers/set';

Set algebra over arrays, Sets, and any iterable: union, intersection, difference, and subset checks, each with a ...By variant that compares records by a key. Array inputs return arrays in first-seen order; a Set as first argument returns a Set. The Helpers and services guide covers the shared conventions.

How do I check whether a user has the permissions a screen needs?

Section titled “How do I check whether a user has the permissions a screen needs?”

isSubset answers yes or no; except lists what is missing, for a precise “you need …” message.

import { except, isSubset } from '@absoluteui/helpers/set';
const granted = new Set(['employee.read', 'leave.read', 'leave.approve']);
const payrollScreen = ['employee.read', 'payroll.read', 'payroll.run'];
isSubset(payrollScreen, granted); // => false
except(payrollScreen, granted); // => ['payroll.read', 'payroll.run']
isSubset(['leave.read', 'leave.approve'], granted); // => true

How do I find who joined and who left between two roster snapshots?

Section titled “How do I find who joined and who left between two roster snapshots?”

The ...By variants compare records by a key, so objects from two API calls match by id even though they are different instances.

import { exceptBy, intersectBy } from '@absoluteui/helpers/set';
const lastMonth = [{ id: 'E-1', name: 'Asha' }, { id: 'E-2', name: 'Ben' }, { id: 'E-3', name: 'Chen' }];
const thisMonth = [{ id: 'E-2', name: 'Ben' }, { id: 'E-3', name: 'Chen' }, { id: 'E-4', name: 'Dana' }];
const byId = (e: { id: string }) => e.id;
exceptBy(thisMonth, lastMonth, byId).map((e) => e.name); // => ['Dana'] // joiners
exceptBy(lastMonth, thisMonth, byId).map((e) => e.name); // => ['Asha'] // leavers
intersectBy(lastMonth, thisMonth, byId).length; // => 2

How do I merge selections from several filters?

Section titled “How do I merge selections from several filters?”

union keeps first-seen order and drops duplicates; symmetricDifference shows what differs between two selections, for example when comparing two saved views.

import { symmetricDifference, union } from '@absoluteui/helpers/set';
const fromDeptFilter = ['E-1', 'E-2', 'E-5'];
const fromSkillFilter = ['E-2', 'E-7'];
union(fromDeptFilter, fromSkillFilter); // => ['E-1', 'E-2', 'E-5', 'E-7']
symmetricDifference(fromDeptFilter, fromSkillFilter); // => ['E-1', 'E-5', 'E-7']

How do I list every combination of options?

Section titled “How do I list every combination of options?”

cartesianProduct builds combinations, for example every site, shift, and role slot for a staffing plan. It is capped at MAX_CARTESIAN_SIZE results.

import { cartesianProduct } from '@absoluteui/helpers/set';
const slots = cartesianProduct([['Pune', 'Oslo'], ['day', 'night'], ['lead']]);
slots.length; // => 4
slots[1]; // => ['Pune', 'night', 'lead']
cartesianProduct([Array.from({ length: 1000 }, (_, i) => i), Array.from({ length: 1001 }, (_, i) => i)]); // => throws HLP_SET_PRODUCT_TOO_LARGE

cartesianProduct

All tuples picking one item from each list, first list varying slowest. Throws HLP_SET_PRODUCT_TOO_LARGE above maxSize.

function cartesianProduct<const T extends readonly unknown[]>(lists: {
readonly [K in keyof T]: Iterable<T[K]>;
}, options?: CartesianProductOptions): {
-readonly [K in keyof T]: T[K];
}[];

Example:

cartesianProduct([[1, 2], ['a', 'b']]); // => [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]

countOccurrences

Occurrence count per item (SameValueZero), in first-occurrence order.

function countOccurrences<T>(items: Collection<T>): Map<T, number>;

Example:

countOccurrences(['a', 'b', 'a']); // => new Map([['a', 2], ['b', 1]])

except

Items of a not in b (set difference).

function except<T>(a: ReadonlySet<T>, b: Collection<T>): Set<T>;
function except<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

except([1, 2, 3], [2]); // => [1, 3]

exceptBy

Items of a whose key does not occur in b, deduplicated by key.

function exceptBy<T>(a: ReadonlySet<T>, b: Collection<T>, key: Key<T>): Set<T>;
function exceptBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): T[];

Example:

exceptBy([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // => [{ id: 1 }]

intersect

Items of a also in b, in a’s order.

function intersect<T>(a: ReadonlySet<T>, b: Collection<T>): Set<T>;
function intersect<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

intersect([3, 1, 2], [2, 3]); // => [3, 2]

intersectBy

Items of a whose key occurs in b, deduplicated by key.

function intersectBy<T>(a: ReadonlySet<T>, b: Collection<T>, key: Key<T>): Set<T>;
function intersectBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): T[];

Example:

intersectBy([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // => [{ id: 2 }]

isDisjoint

True when the collections share no item.

function isDisjoint<T>(a: Collection<T>, b: Collection<T>): boolean;

Example:

isDisjoint([1, 2], [3]); // => true

isDisjointBy

True when the collections share no key.

function isDisjointBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): boolean;

Example:

isDisjointBy([{ id: 1 }], [{ id: 2 }], (x) => x.id); // => true

isSubset

True when every item of a is in b.

function isSubset<T>(a: Collection<T>, b: Collection<T>): boolean;

Example:

isSubset([1, 2], [1, 2, 3]); // => true

isSubsetBy

True when every key of a occurs in b.

function isSubsetBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): boolean;

Example:

isSubsetBy([{ id: 1 }], [{ id: 1 }, { id: 2 }], (x) => x.id); // => true

isSuperset

True when every item of b is in a.

function isSuperset<T>(a: Collection<T>, b: Collection<T>): boolean;

Example:

isSuperset([1, 2, 3], [2]); // => true

isSupersetBy

True when every key of b occurs in a.

function isSupersetBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): boolean;

Example:

isSupersetBy([{ id: 1 }, { id: 2 }], [{ id: 2 }], (x) => x.id); // => true

multisetExcept

Multiset difference: each item appears max(0, count in a - count in b) times.

function multisetExcept<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

multisetExcept([1, 1, 2], [1]); // => [1, 2]

multisetIntersect

Multiset intersection: each item appears min(count in a, count in b) times.

function multisetIntersect<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

multisetIntersect([1, 1, 2], [1, 3]); // => [1]

multisetUnion

Multiset union: each item appears max(count in a, count in b) times, grouped in first-occurrence order.

function multisetUnion<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

multisetUnion([1, 1, 2], [1, 2, 2]); // => [1, 1, 2, 2]

powerSet

Every subset of the distinct items, ordered by binary counting ([] first). Throws HLP_SET_POWERSET_TOO_LARGE when the input has more than maxItems distinct items.

function powerSet<T>(items: Collection<T>, options?: PowerSetOptions): T[][];

Example:

powerSet(['a', 'b']); // => [[], ['a'], ['b'], ['a', 'b']]

setEquals

True when both contain the same distinct items (order and duplicates ignored).

function setEquals<T>(a: Collection<T>, b: Collection<T>): boolean;

Example:

setEquals([1, 2, 2], new Set([2, 1])); // => true

setEqualsBy

True when both contain the same distinct keys.

function setEqualsBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): boolean;

Example:

setEqualsBy([{ id: 1 }], [{ id: 1 }, { id: 1 }], (x) => x.id); // => true

symmetricDifference

Items in exactly one collection: a’s first, then b’s.

function symmetricDifference<T>(a: ReadonlySet<T>, b: Collection<T>): Set<T>;
function symmetricDifference<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

symmetricDifference([1, 2], [2, 3]); // => [1, 3]

symmetricDifferenceBy

Symmetric difference by key.

function symmetricDifferenceBy<T>(a: ReadonlySet<T>, b: Collection<T>, key: Key<T>): Set<T>;
function symmetricDifferenceBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): T[];

Example:

symmetricDifferenceBy([{ id: 1 }, { id: 2 }], [{ id: 2 }, { id: 3 }], (x) => x.id); // => [{ id: 1 }, { id: 3 }]

union

Items in either collection, a first.

function union<T>(a: ReadonlySet<T>, b: Collection<T>): Set<T>;
function union<T>(a: Collection<T>, b: Collection<T>): T[];

Example:

union([1, 2], [2, 3]); // => [1, 2, 3]
union(new Set([1]), [2]); // => new Set([1, 2])

unionBy

Union by key; the first item per key wins.

function unionBy<T>(a: ReadonlySet<T>, b: Collection<T>, key: Key<T>): Set<T>;
function unionBy<T>(a: Collection<T>, b: Collection<T>, key: Key<T>): T[];

Example:

unionBy([{ id: 1, v: 'a' }], [{ id: 1, v: 'b' }, { id: 2 }], (x) => x.id); // => [{ id: 1, v: 'a' }, { id: 2 }]

MAX_CARTESIAN_SIZE

Default maximum number of tuples from cartesianProduct.

const MAX_CARTESIAN_SIZE = 1000000;

MAX_POWER_SET_ITEMS

Default maximum distinct input size for powerSet (2^20 subsets).

const MAX_POWER_SET_ITEMS = 20;

CartesianProductOptions

interface CartesianProductOptions {
readonly maxSize?: number;
}

PowerSetOptions

interface PowerSetOptions {
readonly maxItems?: number;
}