_.times(n, iteratee) runs a function n times and gathers the results into an array. It's the clean way to build a fixed-size list — times(5, () => 0) for five zeros, times(3, (i) => i * i) for [0, 1, 4] — without hand-writing a loop.
Implement times(n, iteratee). Call iteratee(i) for i from 0 to n - 1, collect each return value into an array, and return it. iteratee defaults to returning the index, so times(3) gives [0, 1, 2].
function times(n, iteratee = (i) => i) {
// calls iteratee(0), iteratee(1), ... iteratee(n-1) and returns the results.
}
times(3, (i) => i * 2); // [0, 2, 4]
times(5, () => 'a'); // ['a', 'a', 'a', 'a', 'a']
times(3); // [0, 1, 2] — default iteratee returns the index
times(0, () => 'x'); // []
times(-2, () => 'x'); // [] — n <= 0 produces nothing
iteratee is called with the current index i (0-based).times(n) is [0, 1, ..., n-1].n <= 0 — returns an empty array; the iteratee is never called.n — truncated toward zero, so times(2.9) runs twice.You'll run a function a fixed number of times and gather what it returns — a plain counting loop, with one classic trap to avoid.
You need a list of a known size: five default rows, a board of n cells, the squares [0, 1, 4, 9]. Writing the for loop by hand every time is noise. times packages it: give it a count and a function, and it calls the function once per index and hands you back the array of results. You're rebuilding it as times(n, iteratee).
Count from 0 up to n - 1. At each step, call iteratee with the current index and remember what it returns. When you've done that n times, hand back the collected results in order.
A popular trick is to build an array of length n and map over it:
function timesNaive(n, iteratee) {
return new Array(n).map((_, i) => iteratee(i));
}
This looks clever and does nothing. new Array(3) creates an array with length 3 but no actual elements — three holes. And map skips holes: it only calls its callback for indices that exist, so iteratee is never invoked and you get back another array of three holes, not [0, 1, 2]. (The usual patch is new Array(n).fill().map(...), since fill turns the holes into real undefined slots.) Rather than fight sparse arrays, a plain loop touches every index directly.
function times(n, iteratee = (i) => i) {
// Normalize the count: truncate toward zero and floor at 0 so a negative
// or fractional n behaves (2.9 -> 2, -3 -> 0).
const count = Math.max(Math.trunc(n), 0);
const result = [];
for (let i = 0; i < count; i++) {
// Call the iteratee with the index and collect what it returns.
result.push(iteratee(i));
}
return result;
}
module.exports = { times };
The explicit loop sidesteps the sparse-array trap entirely: it visits every i from 0 to count - 1 and calls iteratee(i) each time, so the function always runs exactly count times. Math.max(Math.trunc(n), 0) normalizes the count up front — truncating a fractional n and clamping a negative one to 0 — so those edges produce an empty array instead of a crash or a wrong length. The default parameter (i) => i makes times(n) return [0, 1, ..., n-1].
Take times(3, (i) => i * 2):
Math.trunc(3) is 3; Math.max(3, 0) is 3.iteratee(0) → 0 * 2 = 0. Push. result = [0].iteratee(1) → 2. Push. result = [0, 2].iteratee(2) → 4. Push. result = [0, 2, 4].3 < 3 is false, stop.Result: [0, 2, 4]. And times(-2): Math.max(Math.trunc(-2), 0) is 0, the loop never runs, and it returns [].
new Array(n).map(...) calls nothing — Array(n) is all holes and map skips holes. Use a real loop, or Array.from({ length: n }, (_, i) => ...), which does visit every index.n to 0 — times(-2) should be [], not an error or a reversed loop. Math.max(count, 0) handles it.n — times(2.9) runs twice, not "2.9 times." Normalize with Math.trunc.n gets n's index. times(3, () => Math.random()) ignores it, but times(3, (i) => i) relies on it.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.
_.times(n, iteratee) runs a function n times and gathers the results into an array. It's the clean way to build a fixed-size list — times(5, () => 0) for five zeros, times(3, (i) => i * i) for [0, 1, 4] — without hand-writing a loop.
Implement times(n, iteratee). Call iteratee(i) for i from 0 to n - 1, collect each return value into an array, and return it. iteratee defaults to returning the index, so times(3) gives [0, 1, 2].
function times(n, iteratee = (i) => i) {
// calls iteratee(0), iteratee(1), ... iteratee(n-1) and returns the results.
}
times(3, (i) => i * 2); // [0, 2, 4]
times(5, () => 'a'); // ['a', 'a', 'a', 'a', 'a']
times(3); // [0, 1, 2] — default iteratee returns the index
times(0, () => 'x'); // []
times(-2, () => 'x'); // [] — n <= 0 produces nothing
iteratee is called with the current index i (0-based).times(n) is [0, 1, ..., n-1].n <= 0 — returns an empty array; the iteratee is never called.n — truncated toward zero, so times(2.9) runs twice.You'll run a function a fixed number of times and gather what it returns — a plain counting loop, with one classic trap to avoid.
You need a list of a known size: five default rows, a board of n cells, the squares [0, 1, 4, 9]. Writing the for loop by hand every time is noise. times packages it: give it a count and a function, and it calls the function once per index and hands you back the array of results. You're rebuilding it as times(n, iteratee).
Count from 0 up to n - 1. At each step, call iteratee with the current index and remember what it returns. When you've done that n times, hand back the collected results in order.
A popular trick is to build an array of length n and map over it:
function timesNaive(n, iteratee) {
return new Array(n).map((_, i) => iteratee(i));
}
This looks clever and does nothing. new Array(3) creates an array with length 3 but no actual elements — three holes. And map skips holes: it only calls its callback for indices that exist, so iteratee is never invoked and you get back another array of three holes, not [0, 1, 2]. (The usual patch is new Array(n).fill().map(...), since fill turns the holes into real undefined slots.) Rather than fight sparse arrays, a plain loop touches every index directly.
function times(n, iteratee = (i) => i) {
// Normalize the count: truncate toward zero and floor at 0 so a negative
// or fractional n behaves (2.9 -> 2, -3 -> 0).
const count = Math.max(Math.trunc(n), 0);
const result = [];
for (let i = 0; i < count; i++) {
// Call the iteratee with the index and collect what it returns.
result.push(iteratee(i));
}
return result;
}
module.exports = { times };
The explicit loop sidesteps the sparse-array trap entirely: it visits every i from 0 to count - 1 and calls iteratee(i) each time, so the function always runs exactly count times. Math.max(Math.trunc(n), 0) normalizes the count up front — truncating a fractional n and clamping a negative one to 0 — so those edges produce an empty array instead of a crash or a wrong length. The default parameter (i) => i makes times(n) return [0, 1, ..., n-1].
Take times(3, (i) => i * 2):
Math.trunc(3) is 3; Math.max(3, 0) is 3.iteratee(0) → 0 * 2 = 0. Push. result = [0].iteratee(1) → 2. Push. result = [0, 2].iteratee(2) → 4. Push. result = [0, 2, 4].3 < 3 is false, stop.Result: [0, 2, 4]. And times(-2): Math.max(Math.trunc(-2), 0) is 0, the loop never runs, and it returns [].
new Array(n).map(...) calls nothing — Array(n) is all holes and map skips holes. Use a real loop, or Array.from({ length: n }, (_, i) => ...), which does visit every index.n to 0 — times(-2) should be [], not an error or a reversed loop. Math.max(count, 0) handles it.n — times(2.9) runs twice, not "2.9 times." Normalize with Math.trunc.n gets n's index. times(3, () => Math.random()) ignores it, but times(3, (i) => i) relies on it.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.