Math
All aggregates accept an optional dot-notation key for objects-of-records.
Aggregates
c.min(key?): numberc.max(key?): numberc.sum(key?): numberc.average(key?): numberc.avg(key?): number // aliasc.median(key?): numbercollect([1, 2, 3, 4, 5]).sum(); // 15collect([{ price: 10 }, { price: 20 }]).sum("price"); // 30collect([{ total: { price: 10 } }]).sum("total.price"); // 10 — dot notationEdge cases
min/maxon an empty collection return0(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, not0.averageof an empty collection isNaN(0 / 0).NaNvalues are skipped silently inmin,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) // primitivesc.plus(key, amount) // keyedc.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?) // +1c.decrement(key?) // -1c.double(key?) // *2c.half(key?) // /2collect([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 untouchedClass 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 oddc.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, 4Counting
c.count(keyOrCallback): number // # items where key resolves truthy, or where callback returns truec.countValue(value): number // # items strictly equal to valuec.countBy(key): Record<string, number> // tally of unique key valuescollect(users).count("email"); // # users with an emailcollect(users).count(u => u.active); // # active userscollect([1, 2, 1, 1, 3]).countValue(1); // 3collect(users).countBy("role"); // { admin: 2, user: 5 }