I have always found the range function missing from JavaScript as it is available in python and others? Is there any concise way to generate range of numbers in ES2015 ?
EDIT: MY question is different from the mentioned duplicate as it is specific to ES2015 and not ECMASCRIPT-5. Also I need the range to be starting from 0 and not specific starting number (though it would be good if that is there)
You can use the spread operator on the keys of a freshly created array.
[...Array(n).keys()]
or
Array.from(Array(n).keys())
The Array.from() syntax is necessary if working with TypeScript
I also found one more intuitive way using Array.from:
const range = n => Array.from({length: n}, (value, key) => key)
Now this range function will return all the numbers starting from 0 to n-1
A modified version of the range to support start and end is:
const range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
EDIT
As suggested by #marco6, you can put this as a static method if it suits your use case
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
and use it as
Array.range(3, 9)
With Delta/Step
smallest and one-liner
[...Array(N)].map((_, i) => from + i * step);
Examples and other alternatives
[...Array(10)].map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10)).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10).keys()).map(i => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
[...Array(10).keys()].map(i => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Array(10).fill(0).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array(10).fill().map((_, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Range Function
const range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
range(0, 9, 2);
//=> [0, 2, 4, 6, 8]
// can also assign range function as static method in Array class (but not recommended )
Array.range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
Array.range(2, 10, 2);
//=> [2, 4, 6, 8, 10]
Array.range(0, 10, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.range(2, 10, -1);
//=> []
Array.range(3, 0, -1);
//=> [3, 2, 1, 0]
As Iterators
class Range {
constructor(total = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
for (let i = 0; i < total; yield from + i++ * step) {}
};
}
}
[...new Range(5)]; // Five Elements
//=> [0, 1, 2, 3, 4]
[...new Range(5, 2)]; // Five Elements With Step 2
//=> [0, 2, 4, 6, 8]
[...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
//=>[10, 8, 6, 4, 2]
[...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of new Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
As Generators Only
const Range = function* (total = 0, step = 1, from = 0) {
for (let i = 0; i < total; yield from + i++ * step) {}
};
Array.from(Range(5, -2, -10));
//=> [-10, -12, -14, -16, -18]
[...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
// Lazy loaded way
const number0toInf = Range(Infinity);
number0toInf.next().value;
//=> 0
number0toInf.next().value;
//=> 1
// ...
From-To with steps/delta
using iterators
class Range2 {
constructor(to = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
}
}
[...new Range2(5)]; // First 5 Whole Numbers
//=> [0, 1, 2, 3, 4, 5]
[...new Range2(5, 2)]; // From 0 to 5 with step 2
//=> [0, 2, 4]
[...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
using Generators
const Range2 = function* (to = 0, step = 1, from = 0) {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
[...Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
let even4to10 = Range2(10, 2, 4);
even4to10.next().value;
//=> 4
even4to10.next().value;
//=> 6
even4to10.next().value;
//=> 8
even4to10.next().value;
//=> 10
even4to10.next().value;
//=> undefined
For numbers 0 to 5
[...Array(5).keys()];
=> [0, 1, 2, 3, 4]
A lot of these solutions build on instantiating real Array objects, which can get the job done for a lot of cases but can't support cases like range(Infinity). You could use a simple generator to avoid these problems and support infinite sequences:
function* range( start, end, step = 1 ){
if( end === undefined ) [end, start] = [start, 0];
for( let n = start; n < end; n += step ) yield n;
}
Examples:
Array.from(range(10)); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Array.from(range(10, 20)); // [ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
i = range(10, Infinity);
i.next(); // { value: 10, done: false }
i.next(); // { value: 11, done: false }
i.next(); // { value: 12, done: false }
i.next(); // { value: 13, done: false }
i.next(); // { value: 14, done: false }
So, in this case, it would be nice if Number object would behave like an Array object with the spread operator.
For instance Array object used with the spread operator:
let foo = [0,1,2,3];
console.log(...foo) // returns 0 1 2 3
It works like this because Array object has a built-in iterator.
In our case, we need a Number object to have a similar functionality:
[...3] //should return [0,1,2,3]
To do that we can simply create Number iterator for that purpose.
Number.prototype[Symbol.iterator] = function *() {
for(let i = 0; i <= this; i++)
yield i;
}
Now it is possible to create ranges from 0 to N with the spread operator.
[...N] // now returns 0 ... N array
http://jsfiddle.net/01e4xdv5/4/
Cheers.
Range with step ES6, that works similar to python list(range(start, stop[, step])):
const range = (start, stop, step = 1) => {
return [...Array(stop - start).keys()]
.filter(i => !(i % Math.round(step)))
.map(v => start + v)
}
Examples:
range(0, 8) // [0, 1, 2, 3, 4, 5, 6, 7]
range(4, 9) // [4, 5, 6, 7, 8]
range(4, 9, 2) // [4, 6, 8]
range(4, 9, 3) // [4, 7]
You can use a generator function, which creates the range lazily only when needed:
function* range(x, y) {
while (true) {
if (x <= y)
yield x++;
else
return null;
}
}
const infiniteRange = x =>
range(x, Infinity);
console.log(
Array.from(range(1, 10)) // [1,2,3,4,5,6,7,8,9,10]
);
console.log(
infiniteRange(1000000).next()
);
You can use a higher order generator function to map over the range generator:
function* range(x, y) {
while (true) {
if (x <= y)
yield x++;
else
return null;
}
}
const genMap = f => gx => function* (...args) {
for (const x of gx(...args))
yield f(x);
};
const dbl = n => n * 2;
console.log(
Array.from(
genMap(dbl) (range) (1, 10)) // [2,4,6,8,10,12,14,16,18,20]
);
If you are fearless you can even generalize the generator approach to address a much wider range (pun intended):
const rangeBy = (p, f) => function* rangeBy(x) {
while (true) {
if (p(x)) {
yield x;
x = f(x);
}
else
return null;
}
};
const lte = y => x => x <= y;
const inc = n => n + 1;
const dbl = n => n * 2;
console.log(
Array.from(rangeBy(lte(10), inc) (1)) // [1,2,3,4,5,6,7,8,9,10]
);
console.log(
Array.from(rangeBy(lte(256), dbl) (2)) // [2,4,8,16,32,64,128,256]
);
Keep in mind that generators/iterators are inherently stateful that is, there is an implicit state change with each invocation of next. State is a mixed blessing.
To support delta
const range = (start, end, delta) => {
return Array.from(
{length: (end - start) / delta}, (v, k) => (k * delta) + start
)
};
How about just mapping ....
Array(n).map((value, index) ....) is 80% of the way there. But for some odd reason it does not work. But there is a workaround.
Array(n).map((v,i) => i) // does not work
Array(n).fill().map((v,i) => i) // does dork
For a range
Array(end-start+1).fill().map((v,i) => i + start) // gives you a range
Odd, these two iterators return the same result: Array(end-start+1).entries() and Array(end-start+1).fill().entries()
You can also do it with a one liner with step support like this one:
((from, to, step) => ((add, arr, v) => add(arr, v, add))((arr, v, add) => v < to ? add(arr.concat([v]), v + step, add) : arr, [], from))(0, 10, 1)
The result is [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9].
This function will return an integer sequence.
const integerRange = (start, end, n = start, arr = []) =>
(n === end) ? [...arr, n]
: integerRange(start, end, start < end ? n + 1 : n - 1, [...arr, n]);
$> integerRange(1, 1)
<- Array [ 1 ]
$> integerRange(1, 3)
<- Array(3) [ 1, 2, 3 ]
$> integerRange(3, -3)
<- Array(7) [ 3, 2, 1, 0, -1, -2, -3 ]
Few more ways to do
// Using `repeat` and `map`
const gen = n => [...'.'.repeat(n)].map((_,i) => i);
console.log('gen ', gen(5));
// Using `repeat` and `split`
const gen2 = n => ' '.repeat(n).split('').map((_,i) => i);
console.log('gen2 ', gen2(5));
// Using `concat` with recursive approach
const gen3 = n => n ? gen3(n-1).concat(n-1) : [];
console.log('gen3 ', gen3(5));
const range = (start, end, step = 1) =>
start > end ? [] : [start].concat(range(start + step, end, step));
console.log('range', range(2, 10,2));
const keys = Array(n).keys();
[...Array.from(keys)].forEach(callback);
in Typescript
Here's another variation that doesn't use Array.
let range = (n, l=[], delta=1) => {
if (n < 0) {
return l
}
else {
l.unshift(n)
return range(n - delta, l)
}
}
Generators now allow you to generate the number sequence lazily and using less memory for large ranges.
While the question specifically states ES2015, I expect a lot of Typescript users will end up here and the conversion to ES is straightforward...
function range(end: number): IterableIterator<number>;
// tslint:disable-next-line:unified-signatures
function range(begin: number, end: number): IterableIterator<number>;
function *range(begin: number, end: number = NaN): IterableIterator<number> {
let num = 0;
if (isNaN(end)) {
end = begin;
} else {
num = begin;
}
while (num < end) {
yield num++;
}
}
The first two function declarations are just to provide more informative completion suggestions in your IDE.
In PHP, you can do...
range(1, 3); // Array(1, 2, 3)
range("A", "C"); // Array("A", "B", "C")
That is, there is a function that lets you get a range of numbers or characters by passing the upper and lower bounds.
Is there anything built-in to JavaScript natively for this? If not, how would I implement it?
Numbers
[...Array(5).keys()];
=> [0, 1, 2, 3, 4]
Character iteration
String.fromCharCode(...[...Array('D'.charCodeAt(0) - 'A'.charCodeAt(0) + 1).keys()].map(i => i + 'A'.charCodeAt(0)));
=> "ABCD"
Iteration
for (const x of Array(5).keys()) {
console.log(x, String.fromCharCode('A'.charCodeAt(0) + x));
}
=> 0,"A" 1,"B" 2,"C" 3,"D" 4,"E"
As functions
function range(size, startAt = 0) {
return [...Array(size).keys()].map(i => i + startAt);
}
function characterRange(startChar, endChar) {
return String.fromCharCode(...range(endChar.charCodeAt(0) -
startChar.charCodeAt(0), startChar.charCodeAt(0)))
}
As typed functions
function range(size:number, startAt:number = 0):ReadonlyArray<number> {
return [...Array(size).keys()].map(i => i + startAt);
}
function characterRange(startChar:string, endChar:string):ReadonlyArray<string> {
return String.fromCharCode(...range(endChar.charCodeAt(0) -
startChar.charCodeAt(0), startChar.charCodeAt(0)))
}
lodash.js _.range() function
_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
String.fromCharCode(..._.range('A'.charCodeAt(0), 'D'.charCodeAt(0) + 1));
=> "ABCD"
Old non es6 browsers without a library:
Array.apply(null, Array(5)).map(function (_, i) {return i;});
=> [0, 1, 2, 3, 4]
console.log([...Array(5).keys()]);
(ES6 credit to nils petersohn and other commenters)
For numbers you can use ES6 Array.from(), which works in everything these days except IE:
Shorter version:
Array.from({length: 20}, (x, i) => i);
Longer version:
Array.from(new Array(20), (x, i) => i);
which creates an array from 0 to 19 inclusive. This can be further shortened to one of these forms:
Array.from(Array(20).keys());
// or
[...Array(20).keys()];
Lower and upper bounds can be specified too, for example:
Array.from(new Array(20), (x, i) => i + *lowerBound*);
An article describing this in more detail: http://www.2ality.com/2014/05/es6-array-methods.html
My new favorite form (ES2015)
Array(10).fill(1).map((x, y) => x + y)
And if you need a function with a step param:
const range = (start, stop, step = 1) =>
Array(Math.ceil((stop - start) / step)).fill(start).map((x, y) => x + y * step)
Another possible implementation suggested by the MDN docs:
// Sequence generator function
// (commonly referred to as "range", e.g. Clojure, PHP etc)
const range = (start, stop, step) =>
Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step))
Here's my 2 cents:
function range(start, end) {
return Array.apply(0, Array(end - 1))
.map((element, index) => index + start);
}
It works for characters and numbers, going forwards or backwards with an optional step.
var range = function(start, end, step) {
var range = [];
var typeofStart = typeof start;
var typeofEnd = typeof end;
if (step === 0) {
throw TypeError("Step cannot be zero.");
}
if (typeofStart == "undefined" || typeofEnd == "undefined") {
throw TypeError("Must pass start and end arguments.");
} else if (typeofStart != typeofEnd) {
throw TypeError("Start and end arguments must be of same type.");
}
typeof step == "undefined" && (step = 1);
if (end < start) {
step = -step;
}
if (typeofStart == "number") {
while (step > 0 ? end >= start : end <= start) {
range.push(start);
start += step;
}
} else if (typeofStart == "string") {
if (start.length != 1 || end.length != 1) {
throw TypeError("Only strings with one character are supported.");
}
start = start.charCodeAt(0);
end = end.charCodeAt(0);
while (step > 0 ? end >= start : end <= start) {
range.push(String.fromCharCode(start));
start += step;
}
} else {
throw TypeError("Only string and number types are supported");
}
return range;
}
jsFiddle.
If augmenting native types is your thing, then assign it to Array.range.
var range = function(start, end, step) {
var range = [];
var typeofStart = typeof start;
var typeofEnd = typeof end;
if (step === 0) {
throw TypeError("Step cannot be zero.");
}
if (typeofStart == "undefined" || typeofEnd == "undefined") {
throw TypeError("Must pass start and end arguments.");
} else if (typeofStart != typeofEnd) {
throw TypeError("Start and end arguments must be of same type.");
}
typeof step == "undefined" && (step = 1);
if (end < start) {
step = -step;
}
if (typeofStart == "number") {
while (step > 0 ? end >= start : end <= start) {
range.push(start);
start += step;
}
} else if (typeofStart == "string") {
if (start.length != 1 || end.length != 1) {
throw TypeError("Only strings with one character are supported.");
}
start = start.charCodeAt(0);
end = end.charCodeAt(0);
while (step > 0 ? end >= start : end <= start) {
range.push(String.fromCharCode(start));
start += step;
}
} else {
throw TypeError("Only string and number types are supported");
}
return range;
}
console.log(range("A", "Z", 1));
console.log(range("Z", "A", 1));
console.log(range("A", "Z", 3));
console.log(range(0, 25, 1));
console.log(range(0, 25, 5));
console.log(range(20, 5, 5));
Simple range function:
function range(start, stop, step) {
var a = [start], b = start;
while (b < stop) {
a.push(b += step || 1);
}
return a;
}
To incorporate the BigInt data type some check can be included, ensuring that all variables are same typeof start:
function range(start, stop, step) {
var a = [start], b = start;
if (typeof start == 'bigint') {
stop = BigInt(stop)
step = step? BigInt(step): 1n;
} else
step = step || 1;
while (b < stop) {
a.push(b += step);
}
return a;
}
To remove values higher than defined by stop e.g. range(0,5,2) will include 6, which shouldn't be.
function range(start, stop, step) {
var a = [start], b = start;
while (b < stop) {
a.push(b += step || 1);
}
return (b > stop) ? a.slice(0,-1) : a;
}
OK, in JavaScript we don't have a range() function like PHP, so we need to create the function which is quite easy thing, I write couple of one-line functions for you and separate them for Numbers and Alphabets as below:
for Numbers:
function numberRange (start, end) {
return new Array(end - start).fill().map((d, i) => i + start);
}
and call it like:
numberRange(5, 10); //[5, 6, 7, 8, 9]
for Alphabets:
function alphabetRange (start, end) {
return new Array(end.charCodeAt(0) - start.charCodeAt(0)).fill().map((d, i) => String.fromCharCode(i + start.charCodeAt(0)));
}
and call it like:
alphabetRange('c', 'h'); //["c", "d", "e", "f", "g"]
Array.range = function(a, b, step){
var A = [];
if(typeof a == 'number'){
A[0] = a;
step = step || 1;
while(a+step <= b){
A[A.length]= a+= step;
}
}
else {
var s = 'abcdefghijklmnopqrstuvwxyz';
if(a === a.toUpperCase()){
b = b.toUpperCase();
s = s.toUpperCase();
}
s = s.substring(s.indexOf(a), s.indexOf(b)+ 1);
A = s.split('');
}
return A;
}
Array.range(0,10);
// [0,1,2,3,4,5,6,7,8,9,10]
Array.range(-100,100,20);
// [-100,-80,-60,-40,-20,0,20,40,60,80,100]
Array.range('A','F');
// ['A','B','C','D','E','F')
Array.range('m','r');
// ['m','n','o','p','q','r']
https://stackoverflow.com/a/49577331/8784402
With Delta/Step
smallest and one-liner
[...Array(N)].map((_, i) => from + i * step);
Examples and other alternatives
[...Array(10)].map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10)).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10).keys()).map(i => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
[...Array(10).keys()].map(i => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Array(10).fill(0).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array(10).fill().map((_, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Range Function
const range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
range(0, 9, 2);
//=> [0, 2, 4, 6, 8]
// can also assign range function as static method in Array class (but not recommended )
Array.range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
Array.range(2, 10, 2);
//=> [2, 4, 6, 8, 10]
Array.range(0, 10, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.range(2, 10, -1);
//=> []
Array.range(3, 0, -1);
//=> [3, 2, 1, 0]
As Iterators
class Range {
constructor(total = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
for (let i = 0; i < total; yield from + i++ * step) {}
};
}
}
[...new Range(5)]; // Five Elements
//=> [0, 1, 2, 3, 4]
[...new Range(5, 2)]; // Five Elements With Step 2
//=> [0, 2, 4, 6, 8]
[...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
//=>[10, 8, 6, 4, 2]
[...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of new Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
As Generators Only
const Range = function* (total = 0, step = 1, from = 0) {
for (let i = 0; i < total; yield from + i++ * step) {}
};
Array.from(Range(5, -2, -10));
//=> [-10, -12, -14, -16, -18]
[...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
// Lazy loaded way
const number0toInf = Range(Infinity);
number0toInf.next().value;
//=> 0
number0toInf.next().value;
//=> 1
// ...
From-To with steps/delta
using iterators
class Range2 {
constructor(to = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
}
}
[...new Range2(5)]; // First 5 Whole Numbers
//=> [0, 1, 2, 3, 4, 5]
[...new Range2(5, 2)]; // From 0 to 5 with step 2
//=> [0, 2, 4]
[...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
using Generators
const Range2 = function* (to = 0, step = 1, from = 0) {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
[...Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
let even4to10 = Range2(10, 2, 4);
even4to10.next().value;
//=> 4
even4to10.next().value;
//=> 6
even4to10.next().value;
//=> 8
even4to10.next().value;
//=> 10
even4to10.next().value;
//=> undefined
For Typescript
class _Array<T> extends Array<T> {
static range(from: number, to: number, step: number): number[] {
return Array.from(Array(Math.floor((to - from) / step) + 1)).map(
(v, k) => from + k * step
);
}
}
_Array.range(0, 9, 1);
https://stackoverflow.com/a/64599169/8784402
Generate Character List with one-liner
const charList = (a,z,d=1)=>(a=a.charCodeAt(),z=z.charCodeAt(),[...Array(Math.floor((z-a)/d)+1)].map((_,i)=>String.fromCharCode(a+i*d)));
console.log("from A to G", charList('A', 'G'));
console.log("from A to Z with step/delta of 2", charList('A', 'Z', 2));
console.log("reverse order from Z to P", charList('Z', 'P', -1));
console.log("from 0 to 5", charList('0', '5', 1));
console.log("from 9 to 5", charList('9', '5', -1));
console.log("from 0 to 8 with step 2", charList('0', '8', 2));
console.log("from α to ω", charList('α', 'ω'));
console.log("Hindi characters from क to ह", charList('क', 'ह'));
console.log("Russian characters from А to Я", charList('А', 'Я'));
For TypeScript
const charList = (p: string, q: string, d = 1) => {
const a = p.charCodeAt(0),
z = q.charCodeAt(0);
return [...Array(Math.floor((z - a) / d) + 1)].map((_, i) =>
String.fromCharCode(a + i * d)
);
};
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Handy function to do the trick, run the code snippet below
function range(start, end, step, offset) {
var len = (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1;
var direction = start < end ? 1 : -1;
var startingPoint = start - (direction * (offset || 0));
var stepSize = direction * (step || 1);
return Array(len).fill(0).map(function(_, index) {
return startingPoint + (stepSize * index);
});
}
console.log('range(1, 5)=> ' + range(1, 5));
console.log('range(5, 1)=> ' + range(5, 1));
console.log('range(5, 5)=> ' + range(5, 5));
console.log('range(-5, 5)=> ' + range(-5, 5));
console.log('range(-10, 5, 5)=> ' + range(-10, 5, 5));
console.log('range(1, 5, 1, 2)=> ' + range(1, 5, 1, 2));
here is how to use it
range (Start, End, Step=1, Offset=0);
inclusive - forward range(5,10) // [5, 6, 7, 8, 9, 10]
inclusive - backward range(10,5) // [10, 9, 8, 7, 6, 5]
step - backward range(10,2,2) // [10, 8, 6, 4, 2]
exclusive - forward range(5,10,0,-1) // [6, 7, 8, 9] not 5,10 themselves
offset - expand range(5,10,0,1) // [4, 5, 6, 7, 8, 9, 10, 11]
offset - shrink range(5,10,0,-2) // [7, 8]
step - expand range(10,0,2,2) // [12, 10, 8, 6, 4, 2, 0, -2]
hope you find it useful.
And here is how it works.
Basically I'm first calculating the length of the resulting array and create a zero filled array to that length, then fill it with the needed values
(step || 1) => And others like this means use the value of step and if it was not provided use 1 instead
We start by calculating the length of the result array using (Math.abs(end - start) + ((offset || 0) * 2)) / (step || 1) + 1) to put it simpler (difference* offset in both direction/step)
After getting the length, then we create an empty array with initialized values using new Array(length).fill(0); check here
Now we have an array [0,0,0,..] to the length we want. We map over it and return a new array with the values we need by using Array.map(function() {})
var direction = start < end ? 1 : 0; Obviously if start is not smaller than the end we need to move backward. I mean going from 0 to 5 or vice versa
On every iteration, startingPoint + stepSize * index will gives us the value we need
--- UPDATE (Thanks to #lokhmakov for simplification) ---
Another version using ES6 generators ( see great Paolo Moretti answer with ES6 generators ):
const RANGE = (x,y) => Array.from((function*(){
while (x <= y) yield x++;
})());
console.log(RANGE(3,7)); // [ 3, 4, 5, 6, 7 ]
Or, if we only need iterable, then:
const RANGE_ITER = (x,y) => (function*(){
while (x <= y) yield x++;
})();
for (let n of RANGE_ITER(3,7)){
console.log(n);
}
// 3
// 4
// 5
// 6
// 7
--- ORGINAL code was: ---
const RANGE = (a,b) => Array.from((function*(x,y){
while (x <= y) yield x++;
})(a,b));
and
const RANGE_ITER = (a,b) => (function*(x,y){
while (x <= y) yield x++;
})(a,b);
Using Harmony spread operator and arrow functions:
var range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);
Example:
range(10, 15);
[ 10, 11, 12, 13, 14, 15 ]
If, on Visual Studio Code, you faced the error:
Type 'IterableIterator' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
Instead of
[...Array(3).keys()]
you can rely on
Array.from(Array(3).keys())
More on downlevelIteration
You can use lodash or Undescore.js range:
var range = require('lodash/range')
range(10)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Alternatively, if you only need a consecutive range of integers you can do something like:
Array.apply(undefined, { length: 10 }).map(Number.call, Number)
// -> [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
In ES6 range can be implemented with generators:
function* range(start=0, end=null, step=1) {
if (end == null) {
end = start;
start = 0;
}
for (let i=start; i < end; i+=step) {
yield i;
}
}
This implementation saves memory when iterating large sequences, because it doesn't have to materialize all values into an array:
for (let i of range(1, oneZillion)) {
console.log(i);
}
Did some research on some various Range Functions.
Checkout the jsperf comparison of the different ways to do these functions. Certainly not a perfect or exhaustive list, but should help :)
The Winner is...
function range(lowEnd,highEnd){
var arr = [],
c = highEnd - lowEnd + 1;
while ( c-- ) {
arr[c] = highEnd--
}
return arr;
}
range(0,31);
Technically its not the fastest on firefox, but crazy speed difference (imho) on chrome makes up for it.
Also interesting observation is how much faster chrome is with these array functions than firefox. Chrome is at least 4 or 5 times faster.
range(start,end,step): With ES6 Iterators
You only ask for an upper and lower bounds. Here we create one with a step too.
You can easily create range() generator function which can function as an iterator. This means you don't have to pre-generate the entire array.
function * range ( start, end, step = 1 ) {
let state = start;
while ( state < end ) {
yield state;
state += step;
}
return;
};
Now you may want to create something that pre-generates the array from the iterator and returns a list. This is useful for functions that accept an array. For this we can use Array.from()
const generate_array = (start,end,step) =>
Array.from( range(start,end,step) );
Now you can generate a static array easily,
const array1 = generate_array(1,10,2);
const array1 = generate_array(1,7);
But when something desires an iterator (or gives you the option to use an iterator) you can easily create one too.
for ( const i of range(1, Number.MAX_SAFE_INTEGER, 7) ) {
console.log(i)
}
Special Notes
If you use Ramda, they have their own R.range as does Lodash
This may not be the best way. But if you are looking to get a range of numbers in a single line of code. For example 10 - 50
Array(40).fill(undefined).map((n, i) => i + 10)
Where 40 is (end - start) and 10 is the start. This should return [10, 11, ..., 50]
Not implemented yet!
Using the new Number.range proposal (stage 1):
[...Number.range(1, 10)]
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(from, to) => [...Array(to - from)].map((_,i)=> i + from)
An interesting challenge would be to write the shortest function to do this. Recursion to the rescue!
function r(a,b){return a>b?[]:[a].concat(r(++a,b))}
Tends to be slow on large ranges, but luckily quantum computers are just around the corner.
An added bonus is that it's obfuscatory. Because we all know how important it is to hide our code from prying eyes.
To truly and utterly obfuscate the function, do this:
function r(a,b){return (a<b?[a,b].concat(r(++a,--b)):a>b?[]:[a]).sort(function(a,b){return a-b})}
I would code something like this:
function range(start, end) {
return Array(end-start).join(0).split(0).map(function(val, id) {return id+start});
}
range(-4,2);
// [-4,-3,-2,-1,0,1]
range(3,9);
// [3,4,5,6,7,8]
It behaves similarly to Python range:
>>> range(-4,2)
[-4, -3, -2, -1, 0, 1]
My personal favorite:
const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
ES6
Use Array.from (docs here):
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
A rather minimalistic implementation that heavily employs ES6 can be created as follows, drawing particular attention to the Array.from() static method:
const getRange = (start, stop) => Array.from(
new Array((stop - start) + 1),
(_, i) => i + start
);
The standard Javascript doesn't have a built-in function to generate ranges. Several javascript frameworks add support for such features, or as others have pointed out you can always roll your own.
If you'd like to double-check, the definitive resource is the ECMA-262 Standard.
Though this is not from PHP, but an imitation of range from Python.
function range(start, end) {
var total = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i += 1) {
total.push(i);
}
return total;
}
console.log(range(10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(range(0, 10)); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(range(5, 10)); // [5, 6, 7, 8, 9]
This one works also in reverse.
const range = ( a , b ) => Array.from( new Array( b > a ? b - a : a - b ), ( x, i ) => b > a ? i + a : a - i );
range( -3, 2 ); // [ -3, -2, -1, 0, 1 ]
range( 1, -4 ); // [ 1, 0, -1, -2, -3 ]
As far as generating a numeric array for a given range, I use this:
function range(start, stop)
{
var array = [];
var length = stop - start;
for (var i = 0; i <= length; i++) {
array[i] = start;
start++;
}
return array;
}
console.log(range(1, 7)); // [1,2,3,4,5,6,7]
console.log(range(5, 10)); // [5,6,7,8,9,10]
console.log(range(-2, 3)); // [-2,-1,0,1,2,3]
Obviously, it won't work for alphabetical arrays.
You can use following one-liner to keep things short and simple
var start = 4;
var end = 20;
console.log(Array(end - start + 1).fill(start).map((x, y) => x + y));