Is there any ECMAScript 6/7 equivalent to underscore’s range
function?
In underscore:
_.range(startPage, endPage + 1);
In ES2015:
Array.from(Array(n), (_, i) => x + i)
Not sure how the ES2015 version works. I would like to know how range in ecmascript of javascript works
Is there any ECMAScript 6/7 equivalent to underscore’s range
function?
In underscore:
_.range(startPage, endPage + 1);
In ES2015:
Array.from(Array(n), (_, i) => x + i)
Not sure how the ES2015 version works. I would like to know how range in ecmascript of javascript works
Share Improve this question edited Nov 8, 2017 at 21:35 Karty asked Nov 8, 2017 at 21:30 KartyKarty 1,3996 gold badges21 silver badges32 bronze badges 2-
1
What exactly is your question here? Are you looking for an ES6 version of
range
? Are you asking for clarification on how the second snippet works? If so, what precisely do you not understand about it? At least try to make an attempt at explaining it yourself. – Sebastian Simon Commented Nov 8, 2017 at 21:33 - I would like to know how range in ecmascript of javascript works – Karty Commented Nov 8, 2017 at 21:35
3 Answers
Reset to default 14The idea is to create an array of length end - start + 1
, and then fill it with the relevant numbers using Array#from.
The Array.from() method creates a new Array instance from an array-like or iterable object.
In this case Array#from needs an object with the length property. Using Array(n)
creates such an object (array). You can also use { length: n }
directly. In this case n = Math.abs(end - start) + 1
.
Array#from accepts a mapFn
callback, a function that can transform the iterated value. The function receives 2 params - the values (which we can ignore in this case), and the index (0 based). Adding start
to the current index will create the numbers in the range.
const range = (start, end) => Array.from(
Array(Math.abs(end - start) + 1),
(_, i) => start + i
);
console.log(range(5, 10));
console.log(range(-10, -5));
console.log(range(-5, 10));
This version will handle reverse range as well (large to small) as well:
const range = (start, end) => {
const inc = (end - start) / Math.abs(end - start);
return Array.from(
Array(Math.abs(end - start) + 1),
(_, i) => start + i * inc
);
};
console.log(range(5, 10));
console.log(range(-5, -10));
console.log(range(10, -5));
Note that the following implementation does not allow for lazy-generated lists:
Array.from(Array(n), (_, i) => x + i)
Imagine that you need a list of 1M numbers:
range(1, 1000000);
Are you going to consume all of them? Maybe not, yet all the numbers have been generated already and they probably left a non-trivial footprint on your memory.
It would be nice if we could get them one by one on demand.
It turns out we can do exactly that with a generator:
function* range(start, end, step = 1) {
for (let value = start; value < end; value += step) {
yield value;
}
}
for (let x of range(1, Infinity)) {
if (x > 10) {
break;
}
console.log(x);
}
Did you notice the range(1, Infinity)
bit?
In a classic implementation where all the numbers are generated in advance, this code wouldn't even run as you would get stuck in an infinite number-generating loop.
As I understand it, the range
method generates an array of numbers starting from start
, stepping with step
(default = 1) until end
. This simple function does just that :-)
const range = (start, end, step = 1) => {
let result = [];
for(let i=0; i<=end; i+=step) {
result.push(i);
}
return result;
};
What is nice here is that you can use decimal step values.
For example:
range(0, 2, 0.5) // [ 0, 0.5, 1, 1.5, 2 ]
range(0,100,20) // [ 0, 20, 40, 60, 80, 100 ]