Skip to content

Math

All aggregates accept an optional dot-notation key for objects-of-records.

Aggregates

c.min(key?): number
c.max(key?): number
c.sum(key?): number
c.average(key?): number
c.avg(key?): number // alias
c.median(key?): number
collect([1, 2, 3, 4, 5]).sum(); // 15
collect([{ price: 10 }, { price: 20 }]).sum("price"); // 30
collect([{ total: { price: 10 } }]).sum("total.price"); // 10 — dot notation

Edge cases

  • min / max on an empty collection return 0 (preserving the legacy reinforcements convention). On a non-empty collection the wrapper computes the true minimum/maximum directly — collections of all-positive numbers return their actual min, not 0.
  • average of an empty collection is NaN (0 / 0).
  • NaN values are skipped silently in min, max, sum, average, median.

Per-element arithmetic

All of these return a NEW collection with the value applied to each element (or to a keyed value).

c.plus(amount) // primitives
c.plus(key, amount) // keyed
c.minus(amount) / minus(key, amount)
c.multiply(amount) / multiply(key, amount)
c.divide(amount) / divide(key, amount)
c.modulus(amount) / modulus(key, amount)
c.increment(key?) // +1
c.decrement(key?) // -1
c.double(key?) // *2
c.half(key?) // /2
collect([10, 20]).plus(5); // [15, 25]
collect([{ age: 20 }, { age: 30 }]).plus("age", 1);
// [{ age: 21 }, { age: 31 }]

Keyed forms — safe by default for plain objects

The keyed forms (plus("key", amount), minus("key", ...), etc.) shallow-clone each plain-object item via an internal cloneForSet helper before calling set(clone, key, value). The source objects are not mutated:

const src = [{ age: 20 }];
collect(src).plus("age", 1);
src; // [{ age: 20 }] — original is untouched

Class instances and nested object references are still passed through by reference (the clone is shallow). If you need deep immutability for nested structures, clone the input deeply before wrapping.

Division / modulus by zero

divide / modulus throw a plain Error when the divisor is zero. The error message is "Cannot divide by zero" / "Cannot have a modulus of zero".

Parity

c.even(key?) // values that are even (or whose keyed value is even)
c.odd(key?) // values that are odd
c.evenIndexes() // items at indices 0, 2, 4, ... (not based on value!)
c.oddIndexes() // items at indices 1, 3, 5, ...
collect([1, 2, 3, 4, 5]).even(); // [2, 4]
collect([1, 2, 3, 4, 5]).evenIndexes(); // [1, 3, 5] — positions 0, 2, 4

Counting

c.count(keyOrCallback): number // # items where key resolves truthy, or where callback returns true
c.countValue(value): number // # items strictly equal to value
c.countBy(key): Record<string, number> // tally of unique key values
collect(users).count("email"); // # users with an email
collect(users).count(u => u.active); // # active users
collect([1, 2, 1, 1, 3]).countValue(1); // 3
collect(users).countBy("role"); // { admin: 2, user: 5 }