Reputation: 20919
Is there a function in JavaScript similar to Python's range()
?
I think there should be a better way than to write the following lines every time:
array = new Array();
for (i = 0; i < specified_len; i++) {
array[i] = i;
}
Upvotes: 165
Views: 123938
Reputation: 528
This is my solution, I post here even if there are already a lots of answers, because I think it is smart and coincise as well as understandable by human being:
let range = (start, stop, step) => [
...Array((stop?stop:start*2)-start).keys().map(x => {
if (stop) x+=start;
if (!((x-start)%step)) return x})].filter(x => (x !== undefined))
My tests:
rang(5) -> [0, 1, 2, 3, 4]
rang(5, 11) -> [5, 6, 7, 8, 9, 10]
rang(5, 11, 2) -> [5, 7, 9]
Does not work with descending arrays:
rang(5, -1, 2) -> Uncaught RangeError: Invalid Array Length
Upvotes: 0
Reputation: 1078
Assuming you need a simple range with a single step:
let range = (start, end)=> {
if(start === end) return [start];
return [start, ...range(start + 1, end)];
}
else
let range = (start, end, step)=> {
if(start === end) return [start];
return [start, ...range(start + step, end, step)];
}
refer to here for more.
Upvotes: 1
Reputation: 66
A bit of concise, inclusive es6 fun. Codepen demo
var rng=(s,e=null,d=1)=>{
if(e==null)var[s,e]=[0,s]//missing e? s is e
if(s>e)d=d<0?d:-d//s,e backwards? might flip sign
return[...Array(((e-s)/d+1) << 0).keys()].map(x=>d*x+s)
}
rng(3) -> [0,1,2,3]
rng(0,2) -> [0,1,2]
rng(4,6) -> [4,5,6]
rng(3,9,3) -> [3,6,9]
rng(10,27,5) -> [10,15,20,25]
rng(7,null,2) -> [0,2,4,6]
rng(3,-2) -> [3,2,1,0,-1,-2]
rng(3,-2,-2) -> [3,1,-1]
rng(3,-2,2) -> [3,1,-1]
rng(42,42) -> [42]
(Remove the +1
from Array() as is useful/compatible.)
Upvotes: 0
Reputation: 11
const range = function*(start, stop, inclusive=false) {
let dx = Math.sign(stop - start);
if (inclusive) stop += dx;
for (let x = start; x !== stop; x += dx) yield x;
}
const arange = (start, stop, inclusive) => [...range(start, stop, inclusive)];
Upvotes: 0
Reputation: 1509
A simple approach in Typescript without error checking. Up and down incl. steprate.
const range = (start: number, end: number | null = null, step: number = 1): number[] =>
[...Array(end === null ? start : Math.abs(end - start)).keys()]
.filter((n: number): boolean => n % step === 0)
.map((n: number): number => (end === null ? n : end < start ? Math.max(start, end) - n : n + start));
Same in Javascript ES6
const range = (start, end = null, step = 1) =>
[...Array(end === null ? start : Math.abs(end - start)).keys()]
.filter((n) => n % step === 0)
.map((n) => (end === null ? n : end < start ? Math.max(start, end) - n : n + start));
Upvotes: 0
Reputation: 844
/**
* range generator
*
* @param {Integer} start - Optional. An integer specifying at which position to start. Default is 0
* @param {Integer} stop - Required. An integer specifying at which position to stop. Excluded.
* @param {Integer} step - Optional. An integer specifying the incrementation. Default is 1
*/
function* range (start, stop, step = 1) {
if (arguments.length === 1) { [start, stop] = [0, start]; }
if (![start, stop, step].every(Number.isInteger)) { throw new TypeError('range needs integer arguments'); }
if ((start - stop) * step >= 0) { return []; }
let check = start > stop ? (a, b) => a > b : (a, b) => a < b;
while (check(start, stop)) { yield start, start += step; }
}
console.log([...range(4)]);
console.log([...range(2, 4)]);
console.log([...range(1, 4, 2)]);
console.log([...range(-4, -1, 1)]);
console.log([...range(10, 4, -2)]);
console.log([...range(-1, -4, -1)]);
Upvotes: 0
Reputation: 20366
const range = (start: number, stop?: number, step: number = 1) => {
if (stop === undefined) {
[start, stop] = [0, start];
}
return Array.from({ length: Math.ceil((stop - start) / step) }, (_, i) => start + step * i);
};
console.log(range(4)); // [0, 1, 2, 3]
console.log(range(3, 6)); // [3, 4, 5]
console.log(range(0, 10, 2)); // [0, 2, 4, 6, 8]
console.log(range(10, 0, -1)); // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
console.log(range(8, 2, -2)); // [8, 6, 4]
console.log(range(8, 2)); // []
console.log(range(8, 2, 2)); // []
console.log(range(1, 5, -1)); // []
console.log(range(1, 5, -2)); // []
console.log(range(6, 1, -2)); // [6, 4, 2]
console.log(range(1, 6, 2)); // [1, 3, 5]
Upvotes: -1
Reputation: 1
Recursion function is the best solution for implementing a something like this.
If you want only to get numbers begin from zero
function range(n) {
if (n > 0){
return [...range(n-1), n];
};
return [0];
};
console.log("range(5) => ", range(5));
For example,
range(5) = [...range(4), 5]
= [...range(3), 4, 5]
= [...range(2), 3, 4, 5]
= [...range(1), 2, 3, 4, 5]
= [...range(0), 1, 2, 3, 4, 5] // range(0) = [0]
= [0, 1, 2, 3, 4, 5] //final answer
This function can also extend as following
function range(start, stop, step=1){
if( stop > start){
return [...range(start, stop-step), stop];
}
return [start];
}
console.log("range(2, 8, 2) => ", range(2, 8, 2));
But note that, unlike in python you have to provide either two or three arguments.
Upvotes: -2
Reputation: 61
Actually, in Python range() returns an iterable object and we know that iterators are more memory efficient than arrays (or lists in Python). So if we want to implement the same concept with exact functionality in JavaScript we can use an iterator object:
class range {
constructor(start, stop, step = 1) {
//check for invalid input
if (stop !== undefined && typeof stop !== 'number'
|| typeof start !== 'number'
|| typeof step !== 'number') {
throw Error('invalid input for range function');
}
//check if second argument is provided
if (stop === undefined) {
stop = start;
start = 0;
}
//initialize the object properties
this.start = start;
this.stop = stop;
this.step = step;
}
//create the iterator object with Symbol.iterator
[Symbol.iterator]() {
return {
current: this.start,
last: this.stop,
step: this.step,
//implement the next() method of the iterator
next() {
if (this.step === 0) {
return { done: true };
} else if (this.step > 0 ? this.current < this.last : this.current > this.last) {
let value = this.current;
this.current += this.step;
return { done: false, value };
} else {
return { done: true };
}
}
};
};
}
and for example we have:
for (const num of new range(1, 10, 2)) {
console.log(num);
}
also we can create an array easily:
let arr = [...new range(10, -5, -1)];
or:
let arr = Array.from(new range(10));
Upvotes: 4
Reputation: 277
function range(start, stop) {
if (typeof stop == 'undefined') {
stop = start;
start = 0;
}
result = [...Array(stop).keys()].slice(start, stop);
return result;
}
Upvotes: 1
Reputation: 1019
Fusing together both answers from @Tadeck and @georg, I came up with this:
function* range(start, stop, step = 1) {
if (stop == null) {
// one param defined
stop = start;
start = 0;
}
for (let i = start; step > 0 ? i < stop : i > stop; i += step) {
yield i;
}
}
To use it in a for loop you need the ES6/JS1.7 for-of loop:
for (let i of range(5)) {
console.log(i);
}
// Outputs => 0 1 2 3 4
for (let i of range(0, 10, 2)) {
console.log(i);
}
// Outputs => 0 2 4 6 8
for (let i of range(10, 0, -2)) {
console.log(i);
}
// Outputs => 10 8 6 4 2
Upvotes: 48
Reputation: 2066
An option for NodeJs is to use a Buffer:
[...Buffer.alloc(5).keys()]
// [ 0, 1, 2, 3, 4 ]
What's nice is that you can iterate directly on the buffer:
Buffer.alloc(5).forEach((_, index) => console.log(index))
// 0
// 1
// 2
// 3
// 4
You can't do that with an uninitialized Array:
Array(5).forEach((_, index) => console.log(index))
// undefined
But, who in their right mind uses a Buffer for a purpose like this ;)
Upvotes: 1
Reputation: 873
pythonic
mimics the Python range
behaviour best it can using JS' generators (yield
), supporting both the range(stop)
and range(start, stop, step)
use cases. In addition, pythonic
's range
function returns an Iterator
object similar to Python that supports map
and filter
, so one could do fancy one-liners like:
import {range} from 'pythonic';
// ...
const results = range(5).map(wouldBeInvokedFiveTimes);
// `results` is now an array containing elements from
// 5 calls to wouldBeInvokedFiveTimes
Install using npm
:
npm install --save pythonic
Disclosure I'm author and maintainer of Pythonic
Upvotes: 8
Reputation: 24329
Here's how i do it
let n = 5
[...Array(n).keys()].map(x=>{console.log(x)})
output
0
1
2
3
4
Upvotes: 0
Reputation: 2780
This is my preferred way. It allows you to specify one or two inputs like in Python.
function range(start, end) {
return Array.from(Array(end||start).keys()).slice(!!end*start)
}
Upvotes: 2
Reputation: 4301
MDN recommends this approach: Sequence generator (range)
// 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));
// Generate numbers range 0..4
console.log("range(0, 4, 1):", range(0, 4, 1));
// [0, 1, 2, 3, 4]
// Generate numbers range 1..10 with step of 2
console.log("\nrange(1, 10, 2):", range(1, 10, 2));
// [1, 3, 5, 7, 9]
// Generate the alphabet using Array.from making use of it being ordered as a sequence
console.log("\nrange('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x))", range('A'.charCodeAt(0), 'Z'.charCodeAt(0), 1).map(x => String.fromCharCode(x)));
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
Upvotes: 6
Reputation: 113
Still no built-in function that is equivalent to range()
, but with the most recent version - ES2015 - you can build your own implementation. Here's a limited version of it. Limited because it doesn't take into account the step parameter. Just min, max.
const range = (min = null, max = null) =>
Array.from({length:max ? max - min : min}, (v,k) => max ? k + min : k)
This is accomplished by the Array.from
method able to build an array from any object that has a length
property. So passing in a simple object with just the length
property will create an ArrayIterator that will yield length
number of objects.
Upvotes: 2
Reputation: 423
Is there a function in JavaScript similar to Python's range()?
As answered before: no, there's not. But you can make your own.
I believe this is an interesting approach for ES6. It works very similar to Python 2.7 range()
, but it's much more dynamic.
function range(start, stop, step = 1)
{
// This will make the function behave as range(stop)
if(arguments.length === 1)
{
return [...Array(arguments[0]).keys()]
}
// Adjusts step to go towards the stop value
if((start > stop && !(step < 0)) ||
(start < stop && !(step > 0)))
{
step *= -1
}
let returnArray = []
// Checks if i is in the interval between start and stop no matter if stop
// is lower than start or vice-versa
for(let i = start; (i-start)*(i-stop) <= 0; i += step)
{
returnArray.push(i)
}
return returnArray
}
This function can behave in three different ways (just like Python's range()):
range(stop)
range(start, stop)
range(start, stop, step)
These examples:
console.log(range(5))
console.log(range(-2, 2))
console.log(range(2, -2))
console.log(range(10, 20, 2))
Will give you the following output:
[ 0, 1, 2, 3, 4 ]
[ -2, -1, 0, 1, 2 ]
[ 2, 1, 0, -1, -2 ]
[ 10, 12, 14, 16, 18, 20 ]
Note that instead of iterating over the array with the in
operator (like python), you have to use of
. Thus the i
variable assumes the value, and not the index, of the array's element.
for(let i of range(5))
{
// do something with i...
}
Upvotes: 1
Reputation:
For a very simple range in ES6:
let range = n => Array.from(Array(n).keys())
From bigOmega's comment, this can be shortened using Spread syntax:
let range = n => [...Array(n).keys()]
Upvotes: 218
Reputation: 154934
A port of the range
function from Python 2 is provided by the underscore.js and lodash utility libraries (along with many other useful tools). Examples copied from the underscore docs:
_.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]
_.range(0);
=> []
Upvotes: 30
Reputation: 3090
Is there a function in JavaScript similar to Python's range()?
All of the solutions here are referring to Python 2's range (probably because of the code example you gave). However in Python 3, the range() method returns an iterator. JavaScript also has iterators and they're more space efficient than generating the whole array and storing it in memory.
So the more accurate representation of Python 3's range(n)
function is Array(n).keys()
.
For example:
for (let i of Array(n).keys()) {
console.log(i) // 0, 1, 2, 3, ..., n
}
One more example (which has already been covered in the other answers). Converting the iterator to an array (ES6):
let ary = [...Array(n).keys()];
// ary = [0, 1, 2, 3, ..., n]
Upvotes: 3
Reputation: 11
No, there is none, but you can make one.
I'm partial to Python3 behavior of range. You will find below JavaScript's implementation of Python's range():
function* range(start=0, end=undefined, step=1) {
if(arguments.length === 1) {end = start, start = 0}
[...arguments].forEach(arg => {
if( typeof arg !== 'number') {throw new TypeError("Invalid argument")}
})
if(arguments.length === 0) {throw new TypeError("More arguments neede")}
if(start >= end) return
yield start
yield* range(start + step, end, step)
}
// Use Cases
console.log([...range(5)])
console.log([...range(2, 5)])
console.log([...range(2, 5, 2)])
console.log([...range(2,3)])
// You can, of course, iterate through the range instance.
Upvotes: 0
Reputation: 215009
2018: this answer keeps getting upvotes, so here's an update. The code below is obsolete, but luckily ES6 standardized generators and the yield
keyword, and they are universally supported across platforms. An example of the lazy range()
using yield
can be found here.
In addition to what's already said, Javascript 1.7+ provides support for iterators and generators which can be used to create a lazy, memory-efficient version of range
, simlar to xrange
in Python2:
function range(low, high) {
return {
__iterator__: function() {
return {
next: function() {
if (low > high)
throw StopIteration;
return low++;
}
}
}
}
}
for (var i in range(3, 5))
console.log(i); // 3,4,5
Upvotes: 36
Reputation: 11
Here is another es6
implementation of the range
// range :: (from, to, step?) -> [Number]
const range = (from, to, step = 1) => {
//swap values if necesery
[from, to] = from > to ? [to, from] : [from, to]
//create range array
return [...Array(Math.round((to - from) / step))]
.map((_, index) => {
const negative = from < 0 ? Math.abs(from) : 0
return index < negative ?
from + index * step :
(index - negative + 1) * step
})
}
range(-20, 0, 5)
.forEach(val => console.log(val))
for(const val of range(5, 1)){
console.log(`value ${val}`)
}
Upvotes: 0
Reputation: 1032
Can be achieved by attaching an iterator to the Number
prototype
Number.prototype[Symbol.iterator] = function* () {
for (var i = 0; i <= this; i++) {
yield i
}
}
[...5] // will result in [0,1,2,3,4,5]
Taken from Kyle Simpson's course Rethinking Asynchronous JavaScript
Upvotes: 24
Reputation: 20238
The following is a natural adaption of Python's range() function to JavaScript:
// Generate range from start (inclusive) to stop (exclusive):
function* range(start, stop, step = 1) {
if (stop === undefined) [start, stop] = [0, start];
if (step > 0) while (start < stop) yield start, start += step;
else if (step < 0) while (start > stop) yield start, start += step;
else throw new RangeError('range() step argument invalid');
}
// Examples:
console.log([...range(3)]); // [0, 1, 2]
console.log([...range(0, 3)]); // [0, 1, 2]
console.log([...range(0, 3, -1)]);// []
console.log([...range(0, 0)]); // []
console.log([...range(-3)]); // []
console.log([...range(-3, 0)]); // [-3, -2, -1]
It supports any argument which can be compared to 0
and stop
and can be incremented by step
. It behaves identical to the Python version when used with numbers not exceeding Number.MAX_SAFE_INTEGER
.
Please note the following corner cases:
[...range(0, 0, 0)]; // RangeError: range() step argument invalid
[...range(Number.MAX_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER + 2)]; // []
[...range(Number.MAX_SAFE_INTEGER + 2, Number.MAX_SAFE_INTEGER + 3)]; // Infinite loop
[...range(0.7, 0.8, 0.1)]; // [0.7, 0.7999999999999999]
[...range('1', '11')]; // ['1']
[...range('2', '22')]; // Infinite loop
In contrast to @Tadeck's, @Volv's and @janka102's answer which return []
, undefined
or enter an infinite loop when step
evaluates to 0
or NaN
, this generator function throws an exception similar to Python's behavior.
Upvotes: 6
Reputation: 5231
Here's a small extension for one of the answers in case you need to specify both starting and ending position of the range:
let range = (start, end) => Array.from(Array(end + 1).keys()).slice(start);
Upvotes: 11
Reputation: 371
For getting an array of size x
, here's an one-liner without using any library
var range = n => Array(n + 1).join(1).split('').map((x, i) => i)
works as
> range(4)
[0, 1, 2, 3]
Upvotes: 5
Reputation: 73
Further refined with ES6 default parameters.
let range = function*(start = 0, stop, step = 1) {
let cur = (stop === undefined) ? 0 : start;
let max = (stop === undefined) ? start : stop;
for (let i = cur; step < 0 ? i > max : i < max; i += step)
yield i
}
Upvotes: 6