Lodash _.mean() method
What you’ll learn
- How
_.mean(array)is reallybaseSum(array, identity) / array.length—a thin wrapper, not a statistics engine. - That empty / null / undefined input returns
NaN, notundefined(a common doc error). - The string-concatenation trap: one stray string and your average turns into garbage (
34010, not20). - How
undefinedelements are skipped from the sum but still counted in the length. - Three runnable labs (
?tryit=1,2,3) covering the basics, the dirty-data trap, and the empty-array fix.
Prerequisites
Skim the Lodash Math hub and _.add() first. _.mean shares the same +-driven coercion quirks as the rest of the Math family—learn them once, they pay off everywhere.
- How
+works in JS: mixing in even one string flips arithmetic into concatenation. NaNsemantics:NaN === NaNisfalse; useNumber.isNaN()orNumber.isFinite().
Overview
The whole implementation is six lines of baseMean: length ? baseSum(array, iteratee) / length : NaN. baseSum walks the array, calling iteratee(value) (here _.identity), and runs a running result + current—skipping only elements where the iteratee returned undefined.
Sum then divide
No Kahan-style precision tricks—just + in a loop, then divide by array.length.
Length counts everything
Even skipped values (undefined) contribute to the divisor. null contributes 0 to the sum.
No type validation
Strings pass through and become concatenations. Sanitize input with .map(Number) before averaging untrusted data.
Syntax
_.mean(array) - array: array (or array-like) of numbers.
- Returns:
number—the arithmetic mean.NaNwhen the input is empty, nullish, or contains an element that poisons the sum. - Need an iteratee? Reach for _.meanBy(): same engine, with a per-element score function or property path.
Basics — clean numeric arrays
The happy path: integers, floats, and a single-element array. Note the floating-point result—Lodash does no precision rounding for you.
import mean from "lodash/mean";
console.log(mean([4, 2, 8, 6])); // 5 (docs example)
console.log(mean([10, 20, 30, 40, 50])); // 30
console.log(mean([42])); // 42 (single-element)
console.log(mean([0.1, 0.2, 0.3])); // 0.20000000000000004
console.log(mean([0.1, 0.2, 0.3]).toFixed(2)); // "0.20" Dirty data — strings, null, undefined
This is where most bugs live. A single string element turns the running sum into a string, and the final divide produces a number that looks plausible but is nonsense (34010, not the 20 you expected). undefined entries get skipped from the sum but still count toward the length.
import mean from "lodash/mean";
console.log(mean([10, "20", 30])); // 34010 — '1020' + 30 = '102030', then /3
console.log(mean(["10", "20", "30"])); // 34010 — same trap
console.log(mean([10, undefined, 20])); // 10 — sum 30, but length is 3
console.log(mean([10, null, 20])); // 10 — null coerces to 0, divisor still 3
console.log(mean([10, NaN, 20])); // NaN — NaN poisons everything
// Safe pattern: coerce + filter first
const dirty = [10, "20", null, "abc", 30];
const clean = dirty.map(Number).filter(Number.isFinite);
console.log(mean(clean)); // 20 Empty / nullish input returns NaN
Many tutorials claim _.mean([]) is undefined. It isn’t—baseMean returns 0 / 0 when the array is empty or missing, which is NaN. Always guard before you display the result.
import mean from "lodash/mean";
console.log(mean([])); // NaN
console.log(mean(null)); // NaN
console.log(mean(undefined)); // NaN
// Pattern: default with Number.isFinite, not || or ??
function safeMean(arr) {
const m = mean(arr);
return Number.isFinite(m) ? m : 0;
}
console.log(safeMean([])); // 0
console.log(safeMean([10, 20, 30])); // 20
// Infinity propagates
console.log(mean([1, Infinity, 2])); // Infinity
console.log(mean([Infinity, -Infinity])); // NaN 📋 _.mean vs native alternatives
| Input | _.mean(arr) | arr.reduce((a,b)=>a+b,0)/arr.length | Notes |
|---|---|---|---|
[4, 2, 8, 6] | 5 | 5 | Identical happy path. |
[] | NaN | NaN (0/0) | Same result, but native reduce-without-init would throw. |
[10, undefined, 20] | 10 | NaN | Lodash silently skips undefined; reduce includes it. |
[10, "20", 30] | 34010 | 34010 | Both fall to the string trap; neither validates. |
[1n, 2n, 3n] | throws | throws | BigInt cannot mix with + on numbers. |
Pitfalls to avoid
String concatenation
One stray string in the array silently converts + to string concatenation. The final divide makes the result look like a number, so the bug hides. Always .map(Number).filter(Number.isFinite) first when the data comes from JSON, forms, or CSV.
It’s NaN, not undefined
Branch on Number.isFinite(result), not on result == null. NaN ?? 0 is still NaN—nullish coalescing does not catch it.
Length still counts skipped slots
undefined elements are dropped from the sum but the divisor is still array.length. Filter them out yourself if you want them excluded from the count.
No rounding for you
_.mean is IEEE-754 like everything else. Apply .toFixed(n) or scale-round-unscale for display.
Throws on BigInt input
_.mean([1n, 2n, 3n]) throws Cannot mix BigInt and other types. Convert to Number if you can afford the precision loss.
❓ FAQ
Summary
- Purpose: arithmetic mean of an array of numbers using
baseSum / length—no statistics, no validation. - Remember:
NaNon empty/null input;undefinedelements skipped from sum but counted in length; strings trigger concatenation; BigInts throw. - Next: Lodash _.meanBy() when you need a per-element score function or property path, or read the official Lodash docs for _.mean.
_.mean([]) returns NaN, not undefined—baseMean literally does 0 / 0 when the array is empty or nullish.
6 people found this page helpful
