JavaScript function similar to Python range()-ThrowExceptions

Exception or error:

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;
}
How to solve:

No, there is none, but you can make one.

JavaScript’s implementation of Python’s range()

Trying to emulate how it works in Python, I would create function similar to this:

function range(start, stop, step) {
    if (typeof stop == 'undefined') {
        // one param defined
        stop = start;
        start = 0;
    }

    if (typeof step == 'undefined') {
        step = 1;
    }

    if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
        return [];
    }

    var result = [];
    for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
        result.push(i);
    }

    return result;
};

See this jsfiddle for a proof.

Comparison between range() in JavaScript and Python

It works in the following way:

  • range(4) returns [0, 1, 2, 3],
  • range(3,6) returns [3, 4, 5],
  • range(0,10,2) returns [0, 2, 4, 6, 8],
  • range(10,0,-1) returns [10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
  • range(8,2,-2) returns [8, 6, 4],
  • range(8,2) returns [],
  • range(8,2,2) returns [],
  • range(1,5,-1) returns [],
  • range(1,5,-2) returns [],

and its Python counterpart works exactly the same way (at least in the mentioned cases):

>>> range(4)
[0, 1, 2, 3]
>>> range(3,6)
[3, 4, 5]
>>> range(0,10,2)
[0, 2, 4, 6, 8]
>>> range(10,0,-1)
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> range(8,2,-2)
[8, 6, 4]
>>> range(8,2)
[]
>>> range(8,2,2)
[]
>>> range(1,5,-1)
[]
>>> range(1,5,-2)
[]

So if you need a function to work similarly to Python’s range(), you can use above mentioned solution.

###

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()]

###

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

###

Fusing together both answers from @Tadeck and @georg, I came up with this:

function* range(start, stop, step = 1) {
    if (typeof stop === 'undefined') {
        // 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(0, 10, 2)) {
    console.log(i);
}
// Outputs => 0 2 4 6 8

###

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);
=> []

###

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

###

Here you go.

This will write (or overwrite) the value of each index with the index number.

Array.prototype.writeIndices = function( n ) {
    for( var i = 0; i < (n || this.length); ++i ) this[i] = i;
    return this;
};

If you don’t provide a number, it will use the current length of the Array.

Use it like this:

var array = [].writeIndices(10);  // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

###

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);

###

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.

###

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
}

###

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]

###

You may use underscore library. It contains dozens of useful functions for working with arrays and many more.

###

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 a custom built Generator object 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

###

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]

###

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}`)
}

###

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.

###

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)];
}

refer to here for more.

###

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()):

  1. range(stop)
  2. range(start, stop)
  3. 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...
}

###

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.

###

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"]

Leave a Reply

Your email address will not be published. Required fields are marked *