Skip to content

Set Operations

Tyneq provides six set-style operators. All are buffering operators - they read the full source before producing output. Each comes in two variants: equality-based and key-based (keySelector).


distinct / distinctBy

Remove duplicate elements.

ts
// Equality-based: uses ===
Tyneq.from([1, 2, 2, 3, 1]).distinct().toArray();
// -> [1, 2, 3]

// Key-based: compares by projected key
const people = [
  { name: "Alice", dept: "eng" },
  { name: "Bob",   dept: "eng" },
  { name: "Carol", dept: "hr" },
];

Tyneq.from(people)
  .distinctBy(p => p.dept)
  .select(p => p.name)
  .toArray();
// -> ["Alice", "Carol"]  (first occurrence per key is kept)

union / unionBy

All distinct elements from both sequences combined.

ts
// Equality-based
Tyneq.from([1, 2, 3]).union([2, 3, 4]).toArray();
// -> [1, 2, 3, 4]

// Key-based
const left = [{ id: 1 }, { id: 2 }];
const right = [{ id: 2 }, { id: 3 }];

Tyneq.from(left)
  .unionBy(right, x => x.id)
  .select(x => x.id)
  .toArray();
// -> [1, 2, 3]

Elements from the left sequence appear first. Duplicates within the left sequence are also removed.


intersect / intersectBy

Elements present in both sequences.

ts
// Equality-based
Tyneq.from([1, 2, 3, 4]).intersect([2, 4, 6]).toArray();
// -> [2, 4]

// Key-based
const a = [{ id: 1 }, { id: 2 }, { id: 3 }];
const b = [{ id: 2 }, { id: 4 }];

Tyneq.from(a)
  .intersectBy(b.map(x => x.id), x => x.id)
  .select(x => x.id)
  .toArray();
// -> [2]

except / exceptBy

Elements in the source that are NOT in the exclusion set.

ts
// Equality-based
Tyneq.from([1, 2, 3, 4]).except([2, 4]).toArray();
// -> [1, 3]

// Key-based
const all = [{ id: 1 }, { id: 2 }, { id: 3 }];
const excluded = [2, 3];

Tyneq.from(all)
  .exceptBy(excluded, x => x.id)
  .select(x => x.id)
  .toArray();
// -> [1]

Equality Semantics

All equality-based variants use SameValueZero semantics (the same as JavaScript's Set). This is like === with one difference: NaN is considered equal to NaN.

ts
const a = { x: 1 };
const b = { x: 1 };
Tyneq.from([a]).union([b]).count(); // -> 2 - a and b are different references

// NaN deduplication: NaN === NaN is false, but SameValueZero treats them as equal
Tyneq.from([NaN, NaN, 1]).distinct().toArray(); // -> [NaN, 1]

When comparing objects by content, use the key-based variants and select the identifying property.


Choosing the Right Variant

NeedOperator
Remove exact duplicates from one sequencedistinct()
Remove duplicates by a propertydistinctBy(key)
All elements from two sequences, no duplicatesunion(other)
All elements by property, no key duplicatesunionBy(other, key)
Elements in both sequencesintersect(other)
Elements whose key is in both sequencesintersectBy(keys, key)
Elements not in another sequenceexcept(other)
Elements whose key is not in another setexceptBy(keys, key)