1626

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?

Kutyel
  • 8,575
  • 3
  • 30
  • 61
alex
  • 479,566
  • 201
  • 878
  • 984
  • 2
    Prototype.js has the [`$R`](http://www.prototypejs.org/api/objectRange) function, but other than that I don't really think so. – Yi Jiang Oct 09 '10 at 02:42
  • This (related) question has some excellent answers: http://stackoverflow.com/questions/6299500/tersest-way-to-create-an-array-of-integers-from-1-20-in-javascript – btk Feb 25 '15 at 14:47
  • `Array.from("ABC") //['A', 'B', 'C']` This is the closest thing I can find for the second part of the question. – Andrew_1510 May 16 '16 at 01:51
  • @Andrew_1510 You could use `split("")` there also – alex May 22 '16 at 17:46
  • 2
    When lover bound is zero this oneliner: `Array.apply(null, { length: 10 }).map(eval.call, Number)` – csharpfolk Jul 25 '16 at 16:32
  • See http://stackoverflow.com/a/38213213/1579667 -> Array.from({length: N}, (v, k) => k+1); – Benj Mar 10 '17 at 09:16
  • 1
    Possible duplicate of [Create a JavaScript array containing 1...N](https://stackoverflow.com/questions/3746725/create-a-javascript-array-containing-1-n) – KyleMit Mar 28 '19 at 20:08
  • btw just for info there's a tc39 proposal for Number.range, which is stage-1 at the moment https://github.com/tc39/proposal-Number.range – Anurag Hazra May 12 '20 at 11:24
  • 1
    No, but you can define the function using: `const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));` (see ['Sequence generator (range)'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#sequence_generator_range) from MSDN) **NOTE**: This function only works if all parameters are specified (ie. `range(1,5,1)` produces the array `[1,2,3,4,5]`, but `range(1,5)` produces an empty array) – Dave F Feb 15 '21 at 08:12
  • It is simply **incredible** that a language as high-level and popular as JS still lacks a straightforward range or [:] syntax in 2023. I can fathom no reason for it other than layers upon layers of bureaucratic red tape. Someone should pressure the ES committee to add such a feature. Newer languages, such as Rust, have no problem adding syntactic sugar when it would help, even though those languages are far more systematic and "close to the bare metal" than JS. – Asker Aug 17 '23 at 16:30

90 Answers90

2629

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)

Fuji
  • 28,214
  • 2
  • 27
  • 29
  • 95
    Because if it's useful anywhere it is probably useful in JS. (JS can do functional programming type stuff, which can benefit from a range(0 statement. That and a thousand other reasons it might be useful in some semirare case) – Lodewijk May 18 '13 at 19:47
  • 1
    An example, say I want to pregenerate palettes of size 1, 2, 3, 4, 5, etc. I'd do something like var palettes = range(1, 20).map(function(n){return generatePalette(n);}); – Eric Hartford Jan 20 '15 at 16:23
  • 2
    Useful Lodash function, but does not answer the second part of this question: how to create a character range. – amergin Oct 13 '15 at 12:59
  • 6
    Any idea why simply using `(new Array(5)).map(function (value, index) { return index; })` wouldn't work? This returns `[undefined × 5]` for me in Chrome DevTools. – Lewis Dec 15 '15 at 21:52
  • 13
    @Lewis Because an array defined with that has *empty* slots that won't be iterated over with `map()` or one of its friends. – alex Dec 15 '15 at 23:09
  • Be aware that you cannot use Array.from in IE (but it probably works in Edge) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from – jocull Sep 14 '16 at 15:02
  • 1
    You also can use the spread operator `[...new Array(5)]` , only working with modern browser or using transpiler (ES2015) – Freez Oct 12 '16 at 18:51
  • 1
    The spread operator is already used in the ES6 example. [...new Array(5)] prints 5 undefined's – Fuji Oct 15 '16 at 07:34
  • 30
    `Array(5).fill()` is also mappable – nils petersohn Mar 21 '17 at 12:54
  • 1
    Here's a worst way to achieve this: Array.apply(null, new Array(5)).map(Number.call.bind(Number)) – Serge Intern Apr 06 '17 at 09:33
  • 10
    `Array.from(Array(5).keys())` is an ES6 alternative that works in typescript without the `downlevelIteration` compiler flag if anyone was looking – Rico Kahler Oct 17 '17 at 13:30
  • 1
    In case this helps anyone: a range with `low` and `high` bounds: `Array.apply(null, Array(bounds.high-bounds.low+1)).map(function (_, i) {return i+bounds.low;});` – Matt Kocaj Nov 06 '17 at 01:33
  • 3
    Just in case, if you want to start the array with 1, then you can do so by passing map function to Array from() `Array.from(Array(10), (_, i) => i + 1) //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]` Source: https://stackoverflow.com/a/33352604/327862 – Mukesh Chapagain Aug 12 '20 at 21:40
  • 1
    Start array size 'n' at whatever 'startAt' number you want by "slicing" off the first numbers using `[...Array(n).keys()].slice(startAt-1)`, .e. `[...Array(7).keys()].slice(4)` for `[4,5,6,7]` – Michael Durrant Aug 12 '20 at 23:49
  • 1
    Indeed `Array(5).fill()` is mappable, and preferable because is WAY more performant (~4x) than the spread of `[...Array(5).keys()]` – Cezar D. May 21 '21 at 12:16
  • 1
    If you have a downlevelIteration warning, [see this answer](https://stackoverflow.com/a/69046160/1248177) – aloisdg Sep 03 '21 at 14:01
  • 1
    a one liner using recursion with `const range = (start, end, inc) => (function r (s, e = end, i = inc) { return s > e ? [] : [s, ...r(s + i)] })(start)` and without `const range = (start, end) => start > end ? [] : [start, ...range(start + 1, end)]` increment – tetotechy Aug 16 '22 at 21:50
  • @tetotechy that's a new approach. I don't find it as easy to read as the current solution so I'll leave it out for now. Good to see other solutions tho. And recursion will lead to a stack overflow in JS if n is greater than 1e4 since JS has no recursion optimization – Fuji Sep 26 '22 at 08:18
  • "As typed functions" Is this typescript or JavaScript? – Daniel Kaplan May 05 '23 at 20:22
  • It is **incredible** that a language as high-level and popular as JS still lacks a straightforward `range` or `[:]` syntax in 2023. – Asker Aug 17 '23 at 16:21
  • Actually, I am curious as to why no standard support for a `range` or `[:]` syntax has been added to JS yet. I can fathom no reason for it other than layers upon layers of bureaucratic red tape. Perhaps someone should pressure the ES committee to add such a feature? It seems long overdue. Some nice new languages, such as Rust, have no problem adding syntactic sugar when it would help, even despite those languages being much more systematic and "closer to the bare metal" than JS. – Asker Aug 17 '23 at 16:26
597

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

Community
  • 1
  • 1
Kristjan Liiva
  • 9,069
  • 3
  • 25
  • 26
  • 77
    The first example can even be simplified to [...Array(20).keys()] – Delapouite Nov 20 '15 at 17:39
  • 51
    Slightly more succinct than the `Array.from()` method, and faster than both: `Array(20).fill().map((_, i) => i)` – Stu Cox Feb 20 '16 at 08:34
  • 11
    @Delapouite @jib And this as well: `Array.from({length: end - start}, (v, k) => k + start)` – Aditya Singh May 15 '16 at 07:11
  • Nifty if you'd like to create array of empty subarrays too (`var matrix = Array.from(new Array(3), () => []);`). – Neurotransmitter Nov 16 '16 at 11:25
  • Some android devices (mainly Samsung) seem to be missing Array.from: `Uncaught TypeError: Object function Array() { [native code] } has no method 'from'`. – mikebridge Dec 13 '17 at 16:02
  • Your longer version is actually shorter if you remove the unneeded "new" before Array. – rosenfeld Jul 17 '18 at 14:27
  • 2
    @icc97 Yes, linters may complain, although in JavaScript omitting a function argument defined to be the same as passing `undefined`, so `fill()` (with no argument) isn’t _wrong_ per se. The fill value isn’t used in that solution, so if you like you could use `fill(0)` to save a few characters. – Stu Cox Jan 16 '19 at 08:17
  • The `Array.from` form could eventually be faster than spread etc. for the original use case on the top (while the spreading version of the answer here doesn't generate what the OP asked). The reason for why `Array.from` could be faster is that the spec doesn't require the materialization of an interim array with `undefined`s, as the callback function (2nd arg of `Array.from`) can directly run as the initial array is being written. Faster, and lower pressure on GC if browsers optimize this as the spec expressly hints at it – Robert Monfera Oct 09 '21 at 22:00
  • As an aside, it is **incredible** that a language as high-level and popular as JS still lacks a straightforward range or [:] syntax in 2023. I can fathom no reason for it other than layers upon layers of bureaucratic red tape. Perhaps someone should pressure the ES committee to add such a feature? Some nice new languages, such as Rust, have no problem adding syntactic sugar when it would help, even despite those languages being much more systematic and "closer to the bare metal" than JS. – Asker Aug 17 '23 at 16:28
257

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))
Kutyel
  • 8,575
  • 3
  • 30
  • 61
  • 3
    The argument you pass into `Array(Math.ceil((stop - start) / step) + 1)`, needs the `+1` at the end, to really mimic php's "inclusive" behaviour. – Johan Dettmar Oct 26 '18 at 08:16
  • Try this: Array(10).fill(1).map((x, i) => i) – Stephen DuMont Jan 25 '19 at 01:30
  • 1
    I fixed @rodfersou's code so that stop means the end position: `let range = (start, stop, step=1) => Array(stop - start + 1).fill(start).map((x, y) => x + y * step)` – ximo Nov 26 '19 at 23:46
  • 1
    FYI [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#sequence_generator_range) recommends a `range` function like the second example here: `const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));` – Jacktose Feb 03 '22 at 21:19
  • 1
    It is simply **incredible** that a language as high-level and popular as JS still lacks a straightforward range or [:] syntax in 2023. I can fathom no reason for it other than layers upon layers of bureaucratic red tape. Perhaps someone should pressure the ES committee to add such a feature? Some nice new languages, such as Rust, have no problem adding syntactic sugar when it would help, even despite those languages being much more systematic and "closer to the bare metal" than JS. – Asker Aug 17 '23 at 16:29
111

Here's my 2 cents:

function range(start, end) {
  return Array.apply(0, Array(end - 1))
    .map((element, index) => index + start);
}
Andrea
  • 553
  • 9
  • 12
jflood.net
  • 2,446
  • 2
  • 21
  • 19
85

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));
mplungjan
  • 169,008
  • 28
  • 173
  • 236
alex
  • 479,566
  • 201
  • 878
  • 984
74

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;
}
Richie Bendall
  • 7,738
  • 4
  • 38
  • 58
Remi
  • 20,619
  • 8
  • 57
  • 41
  • 1
    This doesn't work when `step != 1`, the `while` condition needs to take `step` into account. My updated version with a default `step` value: function range(start, stop, step){ step = step || 1 var a=[start], b=start; while((b+step) < stop){ console.log("b: " + b + ". a: " + a + "."); b+=step; a.push(b); } return a; } – daveharris Oct 25 '17 at 21:51
  • @daveharris I added a default step above, `(step || 1)`. – Mr. Polywhirl May 09 '18 at 14:57
  • i have to say just by looking at it, if you try million records, it'll crash your computer. If not, just try with one more zero. I don't think you can exceed a number with more than 8 zeros. – windmaomao Dec 25 '20 at 19:08
58

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"]
Alireza
  • 100,211
  • 27
  • 269
  • 172
  • 5
    I think there are off-by-one errors in these functions. Should be `Array(end - start + 1)`, and `Array(end.charCodeAt(0) - start.charCodeAt(0) + 1)`. – Paul Apr 05 '18 at 16:59
47
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']
Andrio Skur
  • 755
  • 9
  • 22
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • 5
    You really shouldn't jerry-rig methods onto the `Array` prototype. – miike3459 Oct 08 '19 at 22:01
  • This method only works with integers and characters. If the parameters are null, undefined, NaN, boolean, array, object, etc, this method returns the following error: `undefined method toUpperCase to etc`! – Victor Dec 04 '19 at 06:53
  • As miike3459 wrote, if one day ``Array.range`` is added to standard lib you might have a serious problem. – row Nov 17 '21 at 13:40
45

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)
  );
};
nkitku
  • 4,779
  • 1
  • 31
  • 27
  • As an aside, it is **incredible** that a language as high-level and popular as JS still lacks a straightforward range or [:] syntax in 2023. I can fathom no reason for it other than layers upon layers of bureaucratic red tape. Someone should pressure the ES committee to add such a feature. Newer languages, such as Rust, have no problem adding syntactic sugar when it would help, even though those languages are much more systematic and "close to the bare metal" than JS. – Asker Aug 17 '23 at 16:29
31
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Klesun
  • 12,280
  • 5
  • 59
  • 52
  • 2
    Very neat! Although, it's important to note it doesn't work on any IE or Opera. – Rafael Xavier May 22 '16 at 00:45
  • @RafaelXavier will work on IE with [Array.fill() polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) – mwag Oct 21 '17 at 11:42
29

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
Community
  • 1
  • 1
azerafati
  • 18,215
  • 7
  • 67
  • 72
29

--- 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);
Hero Qu
  • 911
  • 9
  • 10
24

If, on Visual Studio Code, you faced the error:

screenshot

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

Pang
  • 9,564
  • 146
  • 81
  • 122
aloisdg
  • 22,270
  • 6
  • 85
  • 105
22

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 ]
c.P.u1
  • 16,664
  • 6
  • 46
  • 41
19

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);
}
Paolo Moretti
  • 54,162
  • 23
  • 101
  • 92
  • The ES6 part is now the correct answer to this question. I would recommend removing the other parts, which are covered by other answers. – joews Nov 08 '15 at 15:24
  • generators are somewhat strange if used outside a loop though: x=range(1, 10);//{} x;//{}// looks like an empty map WTF!?! x.next().value;// OK 1 ;x[3] // undefined, only with real array – Anona112 Dec 08 '16 at 20:06
  • @Anona112 you can use `Array.from` to convert generators to array instances and inspect the output. – Paolo Moretti Dec 08 '16 at 21:43
18

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.

yoniLavi
  • 2,624
  • 1
  • 24
  • 30
Justin
  • 2,940
  • 3
  • 25
  • 43
18

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

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
15

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]

Edison D'souza
  • 4,551
  • 5
  • 28
  • 39
14

Not implemented yet!

Using the new Number.range proposal (stage 2):

[...Number.range(1, 10)]
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Richie Bendall
  • 7,738
  • 4
  • 38
  • 58
13
(from, to) => [...Array(to - from)].map((_,i)=> i + from)
LKB
  • 457
  • 6
  • 16
12

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})}
Rick Hitchcock
  • 35,202
  • 5
  • 48
  • 79
  • 4
    Short != simple, but simpler is better. Here's an easier to read version: `const range = (a, b) => (a>=b) ? [] : [a, ...range(a+1, b)]`, using ES6 syntax – nafg Dec 26 '16 at 07:27
  • 1
    @nafg: `const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];`. Also upvoting the whole answer for the comment. – 7vujy0f0hy Dec 29 '17 at 16:38
12

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

My personal favorite:

const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
12

ES6

Use Array.from (docs here):

const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
Noor Ul Ain
  • 570
  • 5
  • 9
10

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
);
IsenrichO
  • 4,251
  • 3
  • 18
  • 31
  • As a side note, I've created a Gist in which I made an "enhanced" `getRange()` function of sorts. In particular, I aimed to capture edge cases that might be unaddressed in the bare-bones variant above. Additionally, I added support for alphanumeric ranges. In other words, calling it with two supplied inputs like `'C'` and `'K'` (in that order) returns an array whose values are the sequential set of characters from the letter 'C' (inclusive) through the letter 'K' (exclusive): `getRange('C', 'K'); // => ["C", "D", "E", "F", "G", "H", "I", "J"]` – IsenrichO Mar 14 '17 at 03:10
  • you don't need the `new` keyword – Soldeplata Saketos Mar 14 '19 at 17:41
9

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] 
  • +1 for the fastest. with an array of -36768 - 36768, took 3ms, 2nd place was 13 ms and has IDE red lines. – mjwrazor May 09 '17 at 21:12
9

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.

Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
  • While I'm sure a perfectly good answer in 2010, this should no longer be considered the best approach. You should not extend built in types, like Prototype.js tended to do – Dana Woodman Jul 19 '18 at 03:34
  • @DanaWoodman thanks for bringing this up - I've updated the answer to take out the reference to Prototype.js since that is indeed pretty much obsolete in 2018 – Mike Dinescu Jul 19 '18 at 05:39
  • 66
    Well this didn't help at all. – Pithikos Apr 01 '19 at 19:09
  • 3
    @Pithikos I see this question has been edited since it was originally asked and the OP wanted to know if there is a native range function in JS. – Mike Dinescu Apr 03 '19 at 02:57
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 ]
Rocco Ghielmini
  • 303
  • 5
  • 10
9

In case want to use the range only to repeat a process n times u could simply use this code

[...Array(10)].map((item, index) => ( 
    console.log("item:", index)
))
DINA TAKLIT
  • 7,074
  • 10
  • 69
  • 74
  • This method only works if your range starts at 0. – Henry Floyd Mar 30 '23 at 19:57
  • The goal of this option is clearly mentioned repeat the process n times not to stimulate python range method necessarily, this is helpful in react especially to quickly create n items inside a component. – DINA TAKLIT Mar 31 '23 at 15:27
  • The asker specifically requested a function that could accept upper and lower bounds. This option does not accept a lower bound and therefore does not answer the question. – Henry Floyd Mar 31 '23 at 19:39
  • Do you think that the asker will give an interest to my answer it is published 12 years ago! new answers are to help new quite similar questions, like myself I was looking for a way to create n component inside react app so I was looking for custom range, and I guess some people does and since this question will be the most floating once you search about such a way so it would be very helpful to share an answer here and mostly it is not against the global idea, got me? Think about the value ;). – DINA TAKLIT Mar 31 '23 at 19:53
8

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.

jhaskell
  • 485
  • 7
  • 7
  • Setting `array = []` inside the loop may not give you what you want. – alex May 23 '15 at 02:36
  • @alex, thank you. You're right, I also forgot to increment the "start" parameter on each pass of the loop. It's fixed now. – jhaskell May 24 '15 at 02:56
  • It still won't produce the desired output, if I want range 5-10, it will give me `[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]`, I would expect only the first half of that array. – alex May 24 '15 at 07:55
  • @alex, thank you again, I had not considered a length constraint based on input. See updated version. – jhaskell May 25 '15 at 16:46
8

d3 also has a built-in range function.

See https://github.com/d3/d3-array#range:

d3.range([start, ]stop[, step])

Generates an array containing an arithmetic progression, similar to the Python built-in range. This method is often used to iterate over a sequence of numeric or integer values, such as the indexes into an array. Unlike the Python version, the arguments are not required to be integers, though the results are more predictable if they are due to floating point precision. If step is omitted, it defaults to 1.

Example:

d3.range(10)
// returns [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bob Baxley
  • 3,551
  • 1
  • 22
  • 28
  • I never knew D3 existed. Not going to use their range method but will be using this package. – mjwrazor May 09 '17 at 19:24
  • Thank you so much. I use D3 and was looking for a native JS method, not knowing that I D3 offers it already. – cezar Jul 01 '19 at 07:24
8

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));
Rahul Vala
  • 695
  • 8
  • 17
8

Use this. It creates an array with given amount of values (undefined), in the following example there are 100 indexes, but it is not relevant as here you need only the keys. It uses in the array, 100 + 1, because the arrays are always 0 index based. So if it's given 100 values to generate, the index starts from 0; hence the last value is always 99 not 100.

range(2, 100);

function range(start, end) {
    console.log([...Array(end + 1).keys()].filter(value => end >= value && start <= value ));
}
Don Dilanga
  • 2,722
  • 1
  • 18
  • 20
6

Using Harmony generators, supported by all browsers except IE11:

var take = function (amount, generator) {
    var a = [];

    try {
        while (amount) {
            a.push(generator.next());
            amount -= 1;
        }
    } catch (e) {}

    return a;
};

var takeAll = function (gen) {
    var a = [],
        x;

    try {
        do {
            x = a.push(gen.next());
        } while (x);
    } catch (e) {}

    return a;
};

var range = (function (d) {
    var unlimited = (typeof d.to === "undefined");

    if (typeof d.from === "undefined") {
        d.from = 0;
    }

    if (typeof d.step === "undefined") {
        if (unlimited) {
            d.step = 1;
        }
    } else {
        if (typeof d.from !== "string") {
            if (d.from < d.to) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        } else {
            if (d.from.charCodeAt(0) < d.to.charCodeAt(0)) {
                d.step = 1;
            } else {
                d.step = -1;
            }
        }
    }

    if (typeof d.from === "string") {
        for (let i = d.from.charCodeAt(0); (d.step > 0) ? (unlimited ? true : i <= d.to.charCodeAt(0)) : (i >= d.to.charCodeAt(0)); i += d.step) {
            yield String.fromCharCode(i);
        }
    } else {
        for (let i = d.from; (d.step > 0) ? (unlimited ? true : i <= d.to) : (i >= d.to); i += d.step) {
            yield i;
        }
    }
});

Examples

take

Example 1.

take only takes as much as it can get

take(10, range( {from: 100, step: 5, to: 120} ) )

returns

[100, 105, 110, 115, 120]

Example 2.

to not neccesary

take(10, range( {from: 100, step: 5} ) )

returns

[100, 105, 110, 115, 120, 125, 130, 135, 140, 145]

takeAll

Example 3.

from not neccesary

takeAll( range( {to: 5} ) )

returns

[0, 1, 2, 3, 4, 5]

Example 4.

takeAll( range( {to: 500, step: 100} ) )

returns

[0, 100, 200, 300, 400, 500]

Example 5.

takeAll( range( {from: 'z', to: 'a'} ) )

returns

["z", "y", "x", "w", "v", "u", "t", "s", "r", "q", "p", "o", "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"]

Janus Troelsen
  • 20,267
  • 14
  • 135
  • 196
6

... more range, using a generator function.

function range(s, e, str){
  // create generator that handles numbers & strings.
  function *gen(s, e, str){
    while(s <= e){
      yield (!str) ? s : str[s]
      s++
    }
  }
  if (typeof s === 'string' && !str)
    str = 'abcdefghijklmnopqrstuvwxyz'
  const from = (!str) ? s : str.indexOf(s)
  const to = (!str) ? e : str.indexOf(e)
  // use the generator and return.
  return [...gen(from, to, str)]
}

// usage ...
console.log(range('l', 'w'))
//=> [ 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' ]

console.log(range(7, 12))
//=> [ 7, 8, 9, 10, 11, 12 ]

// first 'o' to first 't' of passed in string.
console.log(range('o', 't', "ssshhhooooouuut!!!!"))
// => [ 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 't' ]

// only lowercase args allowed here, but ...
console.log(range('m', 'v').map(v=>v.toUpperCase()))
//=> [ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' ]

// => and decreasing range ...
console.log(range('m', 'v').map(v=>v.toUpperCase()).reverse())

// => ... and with a step
console.log(range('m', 'v')
          .map(v=>v.toUpperCase())
          .reverse()
          .reduce((acc, c, i) => (i % 2) ? acc.concat(c) : acc, []))

// ... etc, etc.

Hope this is useful.

John Swindin
  • 79
  • 1
  • 1
6

My codegolfing coworker came up with this (ES6), inclusive:

(s,f)=>[...Array(f-s+1)].map((e,i)=>i+s)

non inclusive:

(s,f)=>[...Array(f-s)].map((e,i)=>i+s)
Marc Sloth Eastman
  • 693
  • 1
  • 10
  • 19
5

you can use lodash function _.range(10) https://lodash.com/docs#range

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
lkan
  • 167
  • 1
  • 5
5

Complete ES6 implementation using range([start, ]stop[, step]) signature:

function range(start, stop, step=1){
  if(!stop){stop=start;start=0;}
  return Array.from(new Array(int((stop-start)/step)), (x,i) => start+ i*step)
}

If you want automatic negative stepping, add

if(stop<start)step=-Math.abs(step)

Or more minimalistically:

range=(b, e, step=1)=>{
  if(!e){e=b;b=0}
  return Array.from(new Array(int((e-b)/step)), (_,i) => b<e? b+i*step : b-i*step)
}

If you have huge ranges look at Paolo Moretti's generator approach

Anona112
  • 3,724
  • 4
  • 21
  • 30
  • Replace `!stop` with `typeof stop === 'undefined'`, then replace `int` with `Math.floor`, and add a check `if (start > stop && step > 0)` (otherwise, `range(-3, -10)` throws an exception instead of doing something sane (either flipping the sign of step or returning `[]`)). Otherwise, good! – Ahmed Fasih Dec 07 '16 at 18:34
5

You can also use a generator to produce the sequence. The difference is that each value in the sequence is lazy loaded. spread operator and for of works for the result. The asterisk symbols makes the function to be a generator.

const range = function*(from,to) {   
    for(let i = from; i <= to; i++) yield I;   
};   

[...range(3,5)]// => [3, 4, 5]
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Zohar Chiprut
  • 752
  • 1
  • 8
  • 18
  • This thread is scary. Thanks for providing more or less mechanically sympathetic version. Eg. most answers are leaning towards allocating an Array of (end-start) elements just to get an array of numbers. It's hacky, clever and terrifying and ... a good fuel for Wirth law. I'd just go with helper function with a for loop that returns an array. – Alex Aug 25 '23 at 12:53
5

Op asked for a range, say range(3, 10), so it can be

[...[...Array(10-3).keys()].map(i => i+3)]

returns

[3, 4, 5, 6, 7, 8, 9]
sppc42
  • 2,994
  • 2
  • 31
  • 49
4

Here's a nice short way to do it in ES6 with numbers only (don't know its speed compares):

Array.prototype.map.call(' '.repeat(1 + upper - lower), (v, i) => i + lower)

For a range of single characters, you can slightly modify it:

Array.prototype.map.call(' '.repeat(1 + upper.codePointAt() - lower.codePointAt()), (v, i) => String.fromCodePoint(i + lower.codePointAt()));
Michael Plautz
  • 3,578
  • 4
  • 27
  • 40
4

There's an npm module bereich for that ("bereich" is the German word for "range"). It makes use of modern JavaScript's iterators, so you can use it in various ways, such as:

console.log(...bereich(1, 10));
// => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

const numbers = Array.from(bereich(1, 10));
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

for (const number of bereich(1, 10)) {
  // ...
}

It also supports descending ranges (by simply exchanging min and max), and it also supports steps other than 1.

Disclaimer: I am the author of this module, so please take my answer with a grain of salt.

Golo Roden
  • 140,679
  • 96
  • 298
  • 425
4

Javascript provides a function to create and fill an array from given values, receiving the container array and a map function as parameters:

let arr = Array.from(SOURCE_ARRAY, MAP_FUNCTION);

Since the MAP_FUNCTION provides the value and index for the iteration, it's possible to create an empty array (SOURCE_ARRAY) and fill it using indexes, like this (supossing 10 is your desired lenght):

let arr = Array.from(Array(10), (n, index) => index);

Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].

David
  • 79
  • 2
4

I did a review of the answers here, and noticed the following points:

  • JavaScript doesn't have a built-in solution for this problem
  • Some answers generate an Array of the correct size but of the wrong values
    • e.g. let arr = Array.from( {length:3} ); // gives [null,null,null]
  • Then, a mapping function is used to replace the wrong values with the correct values
    • e.g. arr.map( (e,i) => i ); // gives [0,1,2]
  • Math is required to shift the number range to satisfy the from..to requirement.
    • e.g. arr.map( (e,i) => i+1 ); // gives [1,2,3]
  • For the string version of the problem, both charCodeAt and fromCharCode was needed to map the string to a number then back to a string again.
    • e.g. arr.map( (e,i) => String.fromCharCode( i+"A".charCodeAt(0) ); // gives ["A","B","C"]

There are some simple to some fancy implementations based on some or all of the above. The answers got complicated when they try to pack both the integer and string solutions into a single function. For me, I elected to implement integer and string solutions in their own functions. I justify this because, in practice, you will know what your use case is and you will use the appropriate function directly. I also supply the wrapper function if you want to call it indirectly.

let rangeInt = (from,to) => Array.from( { length: to-from+1 }, (e, i) => i + from );
let rangeChar = (from,to) => Array.from( { length: to.charCodeAt(0)-from.charCodeAt(0)+1 }, (e,i) => String.fromCharCode(i+from.charCodeAt(0)) );
let range = (from,to) =>
    (typeof(from) === 'string' && typeof(to) === 'string') 
    ? rangeChar(from,to)
    : (!to) ? rangeInt(0,from-1) : rangeInt(from,to);

console.log( rangeInt(1,3) ); // gives [1,2,3]
console.log( rangeChar("A","C") ); // gives ["A","B","C"]
console.log( range(1,3) ); // gives [1,2,3]
console.log( range("A","C") ); // gives ["A","B","C"]
console.log( range(3) ); // gives [0,1,2]
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
3

I was surprised to come across this thread and see nothing like my solution (maybe I missed an answer), so here it is. I use a simple range function in ES6 syntax :

// [begin, end[
const range = (b, e) => Array.apply(null, Array(e - b)).map((_, i) => {return i+b;});

But it works only when counting forward (ie. begin < end), so we can modify it slightly when needed like so :

const range = (b, e) => Array.apply(null, Array(Math.abs(e - b))).map((_, i) => {return b < e ? i+b : b-i;});
nha
  • 17,623
  • 13
  • 87
  • 133
3

You can also do the following:

const range = Array.from(Array(size)).map((el, idx) => idx+1).slice(begin, end);
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
abcd1234
  • 59
  • 2
3

None of the examples had tests, implementation for step with an option to produce decreasing values.

export function range(start = 0, end = 0, step = 1) {
    if (start === end || step === 0) {
        return [];
    }

    const diff = Math.abs(end - start);
    const length = Math.ceil(diff / step);

    return start > end
        ? Array.from({length}, (value, key) => start - key * step)
        : Array.from({length}, (value, key) => start + key * step);

}

Tests:

import range from './range'

describe('Range', () => {
    it('default', () => {
        expect(range()).toMatchObject([]);
    })

    it('same values', () => {
        expect(range(1,1)).toMatchObject([]);
    })

    it('step=0', () => {
        expect(range(0,1,0)).toMatchObject([]);
    })

    describe('step=1', () => {
        it('normal', () => {
            expect(range(6,12)).toMatchObject([6, 7, 8, 9, 10, 11]);
        })

        it('reversed', () => {
            expect(range(12,6)).toMatchObject([12, 11, 10, 9, 8, 7]);
        })
    })

    describe('step=5', () => {

        it('start 0 end 60', () => {
            expect(range(0, 60, 5)).toMatchObject([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]);
        })

        it('reversed start 60 end -1', () => {
            expect(range(55, -1, 5)).toMatchObject([55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0]);
        })
    })
})
Marcel Mandatory
  • 1,447
  • 13
  • 25
3

Keeping it simple:

// Generator
function* iter(a, b, step = 1) {
  for (let i = b ? a : 0; i < (b || a); i += step) {
    yield i
  }
}

const range = (a, b, step = 1) =>
  typeof a === 'string'
    ? [...iter(a.charCodeAt(), b.charCodeAt() + 1)].map(n => String.fromCharCode(n))
    : [...iter(a, b, step)]

range(4) // [0, 1, 2, 3]
range(1, 4) // [1, 2, 3]
range(2, 20, 3) // [2, 5, 8, 11, 14, 17]
range('A', 'C') // ['A', 'B', 'C']
Ramon Diogo
  • 1,630
  • 2
  • 14
  • 9
3

In order to work where either given number could be larger I wrote this:

function getRange(start, end) {
  return Array.from({
    length: 1 + Math.abs(end - start)
  }, (_, i) => end > start ? start + i : start - i);
}
GarethAS
  • 331
  • 2
  • 12
3

You can create your own es6 range version

const range = (min, max) => {
  const arr = Array(max - min + 1)
    .fill(0)
    .map((_, i) => i + min);
  return arr;
}

console.log(range(0,5));

console.log(range(2,8))
DINA TAKLIT
  • 7,074
  • 10
  • 69
  • 74
3

Here is the way to implment your own iterable range function.

// implementing range
function range(start, end){
    return {
      from: start,
      to: end,

      [Symbol.iterator]() { 
        this.current = this.from;
        return this;
      },

      next() { 
        if (this.current <= this.to) {
          return { done: false, value: this.current++ };
        } else {
          return { done: true };
        }
      }
    };

}

// iterate over each value
for (let num of range(1,5)) {
  console.log(num); // 1, 2, 3, 4, 5
}
CrackerKSR
  • 1,380
  • 1
  • 11
  • 29
2

A recursive solution to generating integer array within bounds.

function intSequence(start, end, n = start, arr = []) {
  return (n === end) ? arr.concat(n)
    : intSequence(start, end, start < end ? n + 1 : n - 1, arr.concat(n));
}

$> intSequence(1, 1)
<- Array [ 1 ]

$> intSequence(1, 3)
<- Array(3) [ 1, 2, 3 ]

$> intSequence(3, -3)
<- Array(7) [ 3, 2, 1, 0, -1, -2, -3 ]
Zack
  • 294
  • 1
  • 10
2

For function that behaves like python range() function, use this:

function range(min=0, max=null){
    if(max === null){
        max=min;
        min=0;
    }
    var rg=[...Array(max).keys()];
    return rg.slice(min,max);
}   

Yuriy Yakym
  • 3,616
  • 17
  • 30
Adam Jenča
  • 582
  • 7
  • 20
2

My favorite is the generator generateRange with another function getRange to run the generator. An advantage of this compared to many other solutions is that unnecessary arrays are not created multiple times.

function* generateRange(start, end, step = 1) {
    let current = start;
    while (start < end ? current <= end : current >= end) {
        yield current;
        current = start < end ? current + step : current - step;
    }
}

function getRange(start, end, step = 1) {
    return [...generateRange(start, end, step)];
}

console.log(getRange(0, 5)) // [ 0, 1, 2, 3, 4, 5 ]
console.log(getRange(10, 0, 2)) // [ 10, 8, 6, 4, 2, 0 ]
Asesjix
  • 3,891
  • 3
  • 16
  • 19
  • For others info, usage og generateRange here: `for (let i of generateRange(5,10)){console.log(i)}` – Sancarn Oct 17 '22 at 09:50
1

I found a JS range function equivalent to the one in PHP, and works amazingly great here. Works forward & backward, and works with integers, floats and alphabets!

function range(low, high, step) {
  //  discuss at: http://phpjs.org/functions/range/
  // original by: Waldo Malqui Silva
  //   example 1: range ( 0, 12 );
  //   returns 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
  //   example 2: range( 0, 100, 10 );
  //   returns 2: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
  //   example 3: range( 'a', 'i' );
  //   returns 3: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
  //   example 4: range( 'c', 'a' );
  //   returns 4: ['c', 'b', 'a']

  var matrix = [];
  var inival, endval, plus;
  var walker = step || 1;
  var chars = false;

  if (!isNaN(low) && !isNaN(high)) {
    inival = low;
    endval = high;
  } else if (isNaN(low) && isNaN(high)) {
    chars = true;
    inival = low.charCodeAt(0);
    endval = high.charCodeAt(0);
  } else {
    inival = (isNaN(low) ? 0 : low);
    endval = (isNaN(high) ? 0 : high);
  }

  plus = ((inival > endval) ? false : true);
  if (plus) {
    while (inival <= endval) {
      matrix.push(((chars) ? String.fromCharCode(inival) : inival));
      inival += walker;
    }
  } else {
    while (inival >= endval) {
      matrix.push(((chars) ? String.fromCharCode(inival) : inival));
      inival -= walker;
    }
  }

  return matrix;
}

And here is the minified version:

function range(h,c,b){var i=[];var d,f,e;var a=b||1;var g=false;if(!isNaN(h)&&!isNaN(c)){d=h;f=c}else{if(isNaN(h)&&isNaN(c)){g=true;d=h.charCodeAt(0);f=c.charCodeAt(0)}else{d=(isNaN(h)?0:h);f=(isNaN(c)?0:c)}}e=((d>f)?false:true);if(e){while(d<=f){i.push(((g)?String.fromCharCode(d):d));d+=a}}else{while(d>=f){i.push(((g)?String.fromCharCode(d):d));d-=a}}return i};
evilReiko
  • 19,501
  • 24
  • 86
  • 102
1

For a more ruby-like approach with good backward compatibility:

range([begin], end = 0) where begin and end are numbers

var range = function(begin, end) {
  if (typeof end === "undefined") {
    end = begin; begin = 0;
  }
  var result = [], modifier = end > begin ? 1 : -1;
  for ( var i = 0; i <= Math.abs(end - begin); i++ ) {
    result.push(begin + i * modifier);
  }
  return result;
}

Examples:

range(3); //=> [0, 1, 2, 3]
range(-2); //=> [0, -1, -2]
range(1, 2) //=> [1, 2]
range(1, -2); //=> [1, 0, -1, -2]
Christophe Marois
  • 6,471
  • 1
  • 30
  • 32
  • 1
    `typeof` on a variable guaranteed to be set can be replaced with a strict equality check with `undefined` or `void 0` if you're paranoid and not in strict mode. – alex Jan 22 '16 at 08:58
1

Here is my solution that mimics Python. At the bottom you can find some examples how to use it. It works with numbers, just like Python's range:

var assert = require('assert');    // if you use Node, otherwise remove the asserts

var L = {};    // L, i.e. 'list'

// range(start, end, step)
L.range = function (a, b, c) {
    assert(arguments.length >= 1 && arguments.length <= 3);
    if (arguments.length === 3) {
        assert(c != 0);
    }

    var li = [],
        i,
        start, end, step,
        up = true;    // Increasing or decreasing order? Default: increasing.

    if (arguments.length === 1) {
        start = 0;
        end = a;
        step = 1;
    }

    if (arguments.length === 2) {
        start = a;
        end = b;
        step = 1;
    }

    if (arguments.length === 3) {
        start = a;
        end = b;
        step = c;
        if (c < 0) {
            up = false;
        }
    }

    if (up) {
        for (i = start; i < end; i += step) {
            li.push(i);
        }
    } else {
        for (i = start; i > end; i += step) {
            li.push(i);
        }
    }

    return li;
}

Examples:

// range
L.range(0) -> []
L.range(1) -> [0]
L.range(2) -> [0, 1]
L.range(5) -> [0, 1, 2, 3, 4]

L.range(1, 5) -> [1, 2, 3, 4]
L.range(6, 4) -> []
L.range(-2, 2) -> [-2, -1, 0, 1]

L.range(1, 5, 1) -> [1, 2, 3, 4]
L.range(0, 10, 2) -> [0, 2, 4, 6, 8]
L.range(10, 2, -1) -> [10, 9, 8, 7, 6, 5, 4, 3]
L.range(10, 2, -2) -> [10, 8, 6, 4]
alex
  • 479,566
  • 201
  • 878
  • 984
Jabba
  • 19,598
  • 6
  • 52
  • 45
1
// range()              0..10, step=1
// range(max)           0..max, step=1
// range(min,max)       min..max, step=1
// range(min,step,max)  min..max, step=step
// Use:
// console.log(...range(3));
// Array.from(range(5))
// [...range(100)]
// for (const v of range(1,10)) { ... 

function* range(...args) {
    let [min, step, max] = {
        0: [0, 1, 10],
        1: [0, args[0] >= 0 ? 1 : -1, args[0]],
        2: [args[0], args[1] >= args[0] ? 1 : -1, args[1]],
        3: args,
    }[args.length] || [];
    if (min === undefined) throw new SyntaxError("Too many arguments");
    let x = min;
    while (step >= 0 ? x < max : x > max) {
        yield x;
        x += step
    }
}
console.log(...range());      // 0 1 2 3 4 5 6 7 8 9
console.log(...range(3));     // 0 1 2
console.log(...range(2, 5));  // 2 3 4
console.log(...range(5, 2));  // 5 4 3
console.log(...range(3, -3)); // 3 2 1 0 -1 -2
console.log(...range(-3, 3)); // -3 -2 -1 0 1 2
console.log(...range(-5, -2));// -5 -4 -3
console.log(...range(-2, -5));// -2 -3 -4
MrHIDEn
  • 1,723
  • 1
  • 25
  • 23
1

Per my understanding:

  • JS' runtime environment doesn't support Tail Call Optimization. Writing any recursive function to generate a large range is going to bring you here.
  • Creating arrays for looping might not be the best thing to do if we are going to work with large numbers.
  • Writing large loops causes the event queue to slow down.

function range(start, end, step = 1) {
  const _range = _start => f => {
    if (_start < end) {
      f(_start);
      setTimeout(() => _range(_start + step)(f), 0);
    }
  }

  return {
    map: _range(start),
  };
}

range(0, 50000).map(console.log);

This function doesn't raise the aforementioned concerns.

NSaran
  • 561
  • 3
  • 19
1

I just created this polyfill on the Array via Object.defineProperty to make a range for integers or strings. The Object.defineProperty is a safer way to create polyfills.

The safer polyfill

if (!Array.range) {
  Object.defineProperty(Array, 'range', {
    value: function (from, to, step) {
      if (typeof from !== 'number' && typeof from !== 'string') {
        throw new TypeError('The first parameter should be a number or a character')
      }

      if (typeof to !== 'number' && typeof to !== 'string') {
        throw new TypeError('The second parameter should be a number or a character')
      }

      var A = []
      if (typeof from === 'number') {
        A[0] = from
        step = step || 1
        while (from + step <= to) {
          A[A.length] = from += step
        }
      } else {
        var s = 'abcdefghijklmnopqrstuvwxyz'
        if (from === from.toUpperCase()) {
          to = to.toUpperCase()
          s = s.toUpperCase()
        }
        s = s.substring(s.indexOf(from), s.indexOf(to) + 1)
        A = s.split('')
      }
      return A
    }
  })
} else {
  var errorMessage = 'DANGER ALERT! Array.range has already been defined on this browser. '
  errorMessage += 'This may lead to unwanted results when Array.range() is executed.'
  console.log(errorMessage)
}

Examples

Array.range(1, 3)

// Return: [1, 2, 3]
Array.range(1, 3, 0.5)

// Return: [1, 1.5, 2, 2.5, 3]
Array.range('a', 'c')

// Return: ['a', 'b', 'c']
Array.range('A', 'C')

// Return: ['A', 'B', 'C']
Array.range(null)
Array.range(undefined)
Array.range(NaN)
Array.range(true)
Array.range([])
Array.range({})
Array.range(1, null)

// Return: Uncaught TypeError: The X parameter should be a number or a character
Victor
  • 1,904
  • 18
  • 18
  • 2
    It's unwise to modify any built-in objects such as `Array` – Jon Koops Jan 16 '20 at 12:26
  • @JonKoops Can you explain why? – Victor Feb 04 '20 at 14:52
  • https://flaviocopes.com/javascript-why-not-modify-object-prototype/ – Jon Koops Feb 05 '20 at 09:06
  • Good, I was aware of these details on the text you send, that's why I didn't modify the built-in objects in a normal way. I handled the Possible Conflicts scenario inside the algorithmn. You can notice I was aware of this on the "else" statement, which explicit let the user know that the Array.range function was already declared before. I also explained the possible side effects that may happen on this scenario! Therefore, I was aware of all the points mentioned on this text and that's why I created this wiser Pollyfill. So please don't lower the score on that without analyzing it properly. – Victor Feb 08 '20 at 16:24
  • I understand, however that is still not an ideal solution. If any browser vendor ever implements this API this code will simply stop working. – Jon Koops Feb 10 '20 at 09:51
  • 1
    @JonKoops This code will not simply stop working, it is quite the opposite: it will let the developer know as soon as it will stop working. We can even use a report on the Sentry on the test environment (for example) as soon as it stop working in order to instantly inform this issue to the developer and prevent bugs. And if it stop working, the solution is very simple as fast, it is only required to change the name of the function and replace it to let it work again. – Victor Feb 10 '20 at 18:39
  • Right, but the fact remains that an app running in production could suddenly stop operating as intended. I'm sorry, but adding tooling still isn't going to fix the original problem. – Jon Koops Feb 13 '20 at 17:28
  • 1
    Additional check for `typeof from === typeof to` – ion Jul 06 '20 at 16:50
1

Pythonic styled way:

range = (start, end, step) => {
let arr = []
for(let n=start;n<end;n+=(step||1)) arr.push(n)
return arr;
}
Erisan Olasheni
  • 2,395
  • 17
  • 20
1

One liner that can work in either direction:

const range = (a,b)=>Array(Math.abs(a-b)+1).fill(a).map((v,i)=>v+i*(a>b?-1:1));

See in action:

const range = (a,b) => Array(Math.abs(a-b)+1).fill(a).map((v,i)=>v+i*(a>b?-1:1));

console.log(range(1,4));
console.log(range(4,1));
chickens
  • 19,976
  • 6
  • 58
  • 55
1

There is already very good answers given, but I did not see complete usage of ES6 iterator utilized to achieve full implementation of range, so here it is:

/**
 * inspired by Python's built-in range utility function
 * implemented using ES6 Iterable, Iterator  protolols (interfaces)
 */
class Range {
  constructor(...args) {
    this.start = args.length <= 1 ? 0 : args[0];
    this.end = args.length <= 1 ? args[0] || 0 : args[1];
    this.step = args.length <= 2 ? 1 : args[2];
  }

  [Symbol.iterator]() {
    return this;
  }

  next() {
    if (this.end > this.start) {
      const result = { done: false, value: this.start };
      this.start = this.start + this.step;
      return result;
    } else return { done: true, value: undefined };
  }
}

/**
 * Symbol.iterator is part of the couple of inbuilt symbols
 * available in JavaScript. It allows for hooking into the
 * inbuilt for of iteration mechanism. This is why the
 * Symbol.iterator comes into play when talking about
 * iterables and iterators in JavaScript.
 */

function range(...args) {
  return new Range(...args);
}

console.log([...range(4)]);        // [0, 1, 2, 3]
console.log([...range(2, 5)]);     // [2, 3, 4]
console.log([...range(1, 10, 3)]); // [1, 4, 7]
Humoyun Ahmad
  • 2,875
  • 4
  • 28
  • 46
1

The closest I have found is with the radash library:

import { range } from 'radash'

for (let i of range(1, 5)) {
    console.log(i)
}

See documentation here:

range-Radash

freenrg
  • 99
  • 6
1

I am sharing my implementation in case it may help someone.

function Range(start_or_num, end = null, increment = 1) {
    const end_check = end === null
    const start = end_check  ? 0 : start_or_num
    const count = end_check ? start_or_num : Math.round((end - start) / increment) + 1
     const filterFunc = end_check  ?  x => x >= start : x => x < end && x >= start

    return [...Array.from(
        Array(count).keys(), x => increment * (x - 1) + start
    )
    ].filter(filterFunc)
}
// usage
// console.log(Range(4, 10, 2)) // [4, 6, 8]
// console.log(Range(5, 10 )) //[5, 6, 7, 8, 9]
// console.log(Range(10 ))// [0, 1, 2, 3, 4, 5, 6, 7, 8]
Sermet Pekin
  • 357
  • 2
  • 6
  • 1
    Small edit suggestion: change the `Array(count).keys()` to `{length: count}`, and edit the `.from` map fn from using arg `x` to use args `(_, x)` - itll save you creating a duplicate array and its corresponding iterator – Jony Thrive Mar 29 '23 at 23:01
0

Solution:

//best performance
var range = function(start, stop, step) {
    var a = [start];
    while (start < stop) {
        start += step || 1;
        a.push(start);
    }
    return a;
};

//or
var range = function(start, end) {
    return Array(++end-start).join(0).split(0).map(function(n, i) {
        return i+start
    });
}
  • 1
    Best performance has a few things that could be improved, such as setting `step` to a default value outside of the loop. – alex Apr 12 '16 at 15:28
0

My take using conditional ternary operators in the for loop (no argument testing, though).

function range(start,end,step){
   var resar = [];
   for (var i=start;(step<0 ? i>=end:i<=end); i += (step == undefined ? 1:step)){
       resar.push(i);
     };
   return resar;
};
dorvak
  • 9,219
  • 4
  • 34
  • 43
0

If we input something like [4, 2], we’ll get [2, 3, 4] as output, we can work with that.

function createRange(array) {
  var range = [];
  var highest = array.reduce(function(a, b) {
    return Math.max(a, b);
  });
  var lowest = array.reduce(function(a, b) {
    return Math.min(a, b);
  });
  for (var i = lowest; i <= highest; i++) {
    range.push(i);
  }
  return range;
}
jcuenod
  • 55,835
  • 14
  • 65
  • 102
Vinodh Thiagarajan
  • 758
  • 3
  • 9
  • 19
  • `var highest = Math.max.apply(null, array)`. – alex Mar 04 '16 at 23:33
  • or `Math.max(...array)` – alex Mar 18 '16 at 09:35
  • What's wrong with descending order? range`[4, 2]` should return sequence `[4, 3, 2]`. BTW, it assumes the input array might be any length but you pick only two values (array.reduce is an overkill in this case), suppose `createRange(a, b)` would be more handy here – abuduba Mar 22 '16 at 21:37
0

Coded to 2010 specs (ya, it is 2016 with ES6 generators). Here's my take, with options to emulate the Python's range() function.

Array.range = function(start, end, step){
    if (start == undefined) { return [] } // "undefined" check

    if ( (step === 0) )  {  return []; // vs. throw TypeError("Invalid 'step' input")
    }  // "step" == 0  check

    if (typeof start == 'number') { // number check
        if (typeof end == 'undefined') { // single argument input
            end = start;
            start = 0;
            step = 1;
        }
        if ((!step) || (typeof step != 'number')) {
          step = end < start ? -1 : 1;
        }

        var length = Math.max(Math.ceil((end - start) / step), 0);
        var out = Array(length);

        for (var idx = 0; idx < length; idx++, start += step) {
          out[idx] = start;
        }

        // Uncomment to check "end" in range() output, non pythonic
        if ( (out[out.length-1] + step) == end ) { // "end" check
            out.push(end)
        }

    } else { 
        // Historical: '&' is the 27th letter: http://nowiknow.com/and-the-27th-letter-of-the-alphabet/
        // Axiom: 'a' < 'z' and 'z' < 'A'
        // note: 'a' > 'A' == true ("small a > big A", try explaining it to a kid! )

        var st = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&'; // axiom ordering

        if (typeof end == 'undefined') { // single argument input
            end = start;
            start = 'a';
        }

        var first = st.indexOf(start);
        var last = st.indexOf(end);

        if ((!step) || (typeof step != 'number')) {
          step = last < first ? -1 : 1;
        }

        if ((first == -1) || (last == -1 )) { // check 'first' & 'last'
            return []
        }

        var length = Math.max(Math.ceil((last - first) / step), 0);
        var out = Array(length);

        for (var idx = 0; idx < length; idx++, first += step) {
          out[idx] = st[first];
        } 

        // Uncomment to check "end" in range() output, non pythonic
        if ( (st.indexOf(out[out.length-1]) + step ) == last ) { // "end" check
            out.push(end)
        }
    }
    return out;
}

Example:

Array.range(5);       // [0,1,2,3,4,5]
Array.range(4,-4,-2); // [4, 2, 0, -2, -4]
Array.range('a','d'); // ["a", "b", "c", "d"]
Array.range('B','y'); // ["B", "A", "z", "y"], different from chr() ordering
Array.range('f');     // ["a", "b", "c", "d", "e", "f"]
Array.range(-5);      // [], similar to python
Array.range(-5,0)     // [-5,-4-,-3-,-2,-1,0]
Alvin K.
  • 4,329
  • 20
  • 25
0

For letters, he's a simple vanilla JS solution I came up with to generate letter ranges. It's intended to generate arrays of upper- or lowercase letters, only.

function range(first, last) {
    var r = [],
        i = first.charCodeAt(0);
    
    while(i <= last.charCodeAt(0)) {
        r.push(String.fromCharCode(i++));
    }
    
    return r;
}

console.dir(range("a", "f"));
console.dir(range("G", "Z"));
Madbreaks
  • 19,094
  • 7
  • 58
  • 72
0

I would like to add what I would think is a very adjustable version, which is very fast.

const range = (start, end) => {
    let all = [];
    if (typeof start === "string" && typeof end === "string") {
        // Return the range of characters using utf-8 least to greatest
        const s = start.charCodeAt(0);
        const e = end.charCodeAt(0);
        for (let i = s; i <= e; i++) {
            all.push(String.fromCharCode(i));
        }
    } else if (typeof start === "number" && typeof end === "number") {
        // Return the range of numbers from least to greatest
        for(let i = end; i >= start; i--) {
            all.push(i);
        }
    } else {
        throw new Error("Did not supply matching types number or string.");
    }
    return all;
}
// usage
const aTod = range("a", "d");

Also Typescript if you would like

const range = (start: string | number, end: string | number): string[] | number[] => {
    const all: string[] | number[] = [];
    if (typeof start === "string" && typeof end === "string") {
        const s: number = start.charCodeAt(0);
        const e: number = end.charCodeAt(0);
        for (let i = s; i <= e; i++) {
            all.push(String.fromCharCode(i));
        }
    } else if (typeof start === "number" && typeof end === "number") {
        for (let i = end; i >= start; i--) {
            all.push(i);
        }
    } else {
        throw new Error("Did not supply matching types number or string.");
    }
    return all;
}
// Usage
const negTenToten: number[] = range(-10, 10) as number[];

Made with some influence from other answers. User is gone now.

mjwrazor
  • 1,866
  • 2
  • 26
  • 42
  • `Array.prototype.reverse()` is expensive though for any decently long range. – alex May 10 '17 at 14:34
  • @alex I will retract my statement on that then. But I will leave the block as is since adding in `< | > | === |` logic would be rather simple. I did say easily adjustable. – mjwrazor May 10 '17 at 14:51
0

Here is a simple approach based on @benmcdonald and others, more than one line though...

let K = [];
for (i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) {
  K.push(String.fromCharCode(i))
};
console.log(K);
0

Here is a definition of a range function that behaves exactly like Python's range type except that this one is not lazy. It should be easy to turn it into a generator.

The arguments to the range constructor must be numbers. If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0. If step is zero, an error is raised.

range = (start, stop, step=1) => {
    if(step === 0) throw new Error("range() arg 3 must not be zero");

    const noStart = stop == null;
    stop = noStart ? start : stop;
    start = noStart ? 0 : start;
    const length = Math.ceil(((stop - start) / step));

    return Array.from({length}, (_, i) => (i * step) + start);
}

console.log(range(-10, 10, 2));
//output [Array] [-10,-8,-6,-4,-2,0,2,4,6,8]
console.log(range(10));
// [Array] [0,1,2,3,4,5,6,7,8,9]
console.log(3, 12);
// [Array] [3,4,5,6,7,8,9,10,11]
dmmfll
  • 2,666
  • 2
  • 35
  • 41
0

A range with a defined hard int has a ton of answers, but what if you don't know that step and you want a number of steps in-between instead?

I wrote this code to do that. It's pretty self-explanatory.

const stepScale = (min, max, numberOfSteps) => {
  const _numberOfSteps = numberOfSteps - 1
  const scaleBy = (max - min) / _numberOfSteps

  const arr = []
  for (let i = 0; i <= _numberOfSteps; i += 1) {
    arr.push(min + scaleBy * i)
  }
  return arr
}

export default stepScale
stepScale(5, 10, 4)
// [5, 6.666666666666667, 8.333333333333334, 10]

For npm at https://npm.im/@universalstandard/step-scale

corysimmons
  • 7,296
  • 4
  • 57
  • 65
0

My implementation

export function stringRange(a: string, b: string) {
    let arr = [a + ''];

    const startPrefix = a.match(/([\D])+/g);
    const endPrefix = b.match(/([\D])+/g);

    if ((startPrefix || endPrefix) && (Array.isArray(startPrefix) && startPrefix[0]) !== (Array.isArray(endPrefix) && endPrefix[0])) {
        throw new Error('Series number does not match');
    }

    const startNum = a.match(/([\d])+/g);
    const endNum = b.match(/([\d])+/g);

    if (!startNum || !endNum) {
        throw new Error('Range is not valid');
    }

    let start = parseInt(startNum[0], 10);
    let end = parseInt(endNum[0], 10);

    if (start > end) {
        throw new Error('Ending value should be lessesr that starting value');
    }

    while (start !== end) {
        start++;
        arr.push(startPrefix ? startPrefix[0] + (start + '').padStart(startNum[0].length, '0') : start + '');

    }

    return arr;
}

Sample Result

// console.log(range('0', '10'));
// console.log(range('10', '10')); 
// console.log(range('10', '20'));
// console.log(range('10', '20000'));
// console.log(range('ABC10', 'ABC23'));
// console.log(range('ABC10', 'ABC2300'));
// console.log(range('ABC10', 'ABC09')); --> Failure case
// console.log(range('10', 'ABC23')); --> Failure case
// console.log(range('ABC10', '23')); --> Failure case
Aravin
  • 6,605
  • 5
  • 42
  • 58
0

Setup with TypeScript (app wide):

declare global {
  interface Function {
    range(count: number, start_with: number): number[];
  }
}

Function.prototype.range = function (
  count: number,
  start_with: number = 0
): number[] {
  return [...Array(count).keys()].map((key) => key + start_with);
};

Setup with JS:

Function.prototype.range = function(count, start_with=0){
    return [...Array(count).keys()].map((key) => key + start_with);
}

Use example:

Function.range(2,0) //Will return [0,1]
Function.range(2,1) //Will return [1,2]
Function.range(2,-1) //Will return [-1,0]
Vladimir Djuricic
  • 4,323
  • 1
  • 21
  • 22
0
/**
 * @param {!number|[!number,!number]} sizeOrRange Can be the `size` of the range (1st signature) or a
 *   `[from, to]`-shape array (2nd signature) that represents a pair of the *starting point (inclusive)* and the
 *   *ending point (exclusive)* of the range (*mathematically, a left-closed/right-open interval: `[from, to)`*).
 * @param {!number} [fromOrStep] 1st signature: `[from=0]`. 2nd signature: `[step=1]`
 * @param {!number} [stepOrNothing] 1st signature: `[step=1]`. 2nd signature: NOT-BEING-USED
 * @example
 * range(5) ==> [0, 1, 2, 3, 4] // size: 5
 * range(4, 5)    ==> [5, 6, 7, 8]  // size: 4, starting from: 5
 * range(4, 5, 2) ==> [5, 7, 9, 11] // size: 4, starting from: 5, step: 2
 * range([2, 5]) ==> [2, 3, 4] // [2, 5) // from: 2 (inclusive), to: 5 (exclusive)
 * range([1, 6], 2) ==> [1, 3, 5] // from: 1, to: 6, step: 2
 * range([1, 7], 2) ==> [1, 3, 5] // from: 1, to: 7 (exclusive), step: 2
 * @see {@link https://stackoverflow.com/a/72388871/5318303}
 */
export function range (sizeOrRange, fromOrStep, stepOrNothing) {
  let from, to, step, size
  if (sizeOrRange instanceof Array) { // 2nd signature: `range([from, to], step)`
    [from, to] = sizeOrRange
    step = fromOrStep ?? 1
    size = Math.ceil((to - from) / step)
  } else { // 1st signature: `range(size, from, step)`
    size = sizeOrRange
    from = fromOrStep ?? 0
    step = stepOrNothing ?? 1
  }
  return Array.from({length: size}, (_, i) => from + i * step)
}

Examples:

console.log(
  range(5), // [0, 1, 2, 3, 4] // size: 5
  range([2, 5]), // [2, 3, 4] // [2, 5) // from: 2 (inclusive), to: 5 (exclusive)
  range(4, 2), // [2, 3, 4, 5] // size: 4, starting from: 2
  range([1, 6], 2), // [1, 3, 5] // from: 1, to: 6, step: 2
  range([1, 7], 2), // [1, 3, 5] // from: 1, to: 7 (exclusive), step: 2
)
<script>
  function range (sizeOrRange, fromOrStep, stepOrNothing) {
    let from, to, step, size
    if (sizeOrRange instanceof Array) { // 2nd signature: `range([from, to], step)`
      [from, to] = sizeOrRange
      step = fromOrStep ?? 1
      size = Math.ceil((to - from) / step)
    } else { // 1st signature: `range(size, from, step)`
      size = sizeOrRange
      from = fromOrStep ?? 0
      step = stepOrNothing ?? 1
    }
    return Array.from({ length: size }, (_, i) => from + i * step)
  }
</script>
Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100
0

A typescript function to closely replicate

/**
 * Create a generator from 0 to stop, useful for iteration. Similar to range in Python.
 * See: https://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp
 * See: https://docs.python.org/3/library/stdtypes.html#ranges
 * @param {number | BigNumber} stop
 * @returns {Iterable<number>}
 */
export function range(stop: number | BigNumber): Iterable<number>
/**
 * Create a generator from start to stop, useful for iteration. Similar to range in Python.
 * See: https://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp
 * See: https://docs.python.org/3/library/stdtypes.html#ranges
 * @param {number | BigNumber} start
 * @param {number | BigNumber} stop
 * @returns {Iterable<number>}
 */
export function range(
  start: number | BigNumber,
  stop: number | BigNumber,
): Iterable<number>

/**
 * Create a generator from start to stop while skipping every step, useful for iteration. Similar to range in Python.
 * See: https://stackoverflow.com/questions/3895478/does-javascript-have-a-method-like-range-to-generate-a-range-within-the-supp
 * See: https://docs.python.org/3/library/stdtypes.html#ranges
 * @param {number | BigNumber} start
 * @param {number | BigNumber} stop
 * @param {number | BigNumber} step
 * @returns {Iterable<number>}
 */
export function range(
  start: number | BigNumber,
  stop: number | BigNumber,
  step: number | BigNumber,
): Iterable<number>
export function* range(a: unknown, b?: unknown, c?: unknown): Iterable<number> {
  const getNumber = (val: unknown): number =>
    typeof val === 'number' ? val : (val as BigNumber).toNumber()
  const getStart = () => (b === undefined ? 0 : getNumber(a))
  const getStop = () => (b === undefined ? getNumber(a) : getNumber(b))
  const getStep = () => (c === undefined ? 1 : getNumber(c))

  for (let i = getStart(); i < getStop(); i += getStep()) {
    yield i
  }
}
Daniel Kobe
  • 9,376
  • 15
  • 62
  • 109
0

handle ranges that run in either ascending or descending order:

const range = (start, end) => (
  (end > start)
    ? [...Array((end - start + 1)).keys()].map((k) => (k + start))
    : [...Array((start - end + 1)).keys()].map((k) => (k + end)).reverse()
);
console.log(range(3, 5));
console.log(range(5, 3));
grenade
  • 31,451
  • 23
  • 97
  • 126
0

Try the Iterator.range stage 2 proposal's polyfill.

[...Iterator.range(0, 5)]; // [0, 1, 2, 3, 4]
Knu
  • 14,806
  • 5
  • 56
  • 89
-1

just made something like this as an exercise in Eloquent JavaScript

function range(start, end, step) {
  var ar = [];
  if (start < end) {
    if (arguments.length == 2) step = 1;
    for (var i = start; i <= end; i += step) {
      ar.push(i);
    }
  }
  else {
    if (arguments.length == 2) step = -1;
    for (var i = start; i >= end; i += step) {
      ar.push(i);
    }
  }
  return ar;
}
johnjullies
  • 745
  • 1
  • 8
  • 22
-1

You can use a function with an array, a for loop, and a Math.random() variable to solve that. The for loop pushes numbers into the array, which will contain all the numbers in your range. Then the Math.random() randomly selects one, based on the array's length.

function randNumInRange(min, max) {
  var range = []
  for(var count = min; count <= max; count++) {
    range.push(count);
  }
  var randNum = Math.floor(Math.random() * range.length);
  alert(range[randNum]);
}
jason
  • 11
  • As @btk posted, there are many approaches in this [related post](http://stackoverflow.com/questions/6299500/tersest-way-to-create-an-array-of-integers-from-1-20-in-javascript) – Shawn Mehan Sep 13 '15 at 19:41
-1

There isn't a native method. But you can do it with filter method of Array.

var range = (array, start, end) =>
      array.filter((element, index)=>index>=start && index <= end)


alert( range(['a','h','e','l','l','o','s'],1,5) )
// ['h','e','l','l','o']
jules3c
  • 45
  • 2
-1

I prefer the way below

var range = function(x, y) {
    return Array(y - x+1).fill(x).map((a, b) => {return a+b}).filter(i => i >= x);
};
console.log(range(3, 10));
Vivek Maru
  • 8,347
  • 1
  • 24
  • 34
  • For the love of everything holy, please don't mess with Object.prototype. It causes more pain than it's worth. – Doug Dec 08 '17 at 05:51
-1

This is what I use for numbers ranges:

const rangeFrom0 = end => [...Array(end)].map((_, index) => index);

or

const rangeExcEnd = (start, step, end) => [...Array(end - start + 1)]
   .map((_, index) => index + start)
   .filter(x => x % step === start % step);
danginkgo
  • 1
  • 5
-1
Array.from(Array((m - n + 1)), (v, i) => n + i); // m > n and both of them are integers.
dabeng
  • 1,340
  • 17
  • 7
  • 5
    While this code may resolve the OP's issue, it is best to include an explanation as to how your code addresses the OP's issue. In this way, future visitors can learn from your post, and apply it to their own code. SO is not a coding service, but a resource for knowledge. Also, high quality, complete answers are more likely to be upvoted. These features, along with the requirement that all posts are self-contained, are some of the strengths of SO as a platform, that differentiates it from forums. You can edit to add additional info &/or to supplement your explanations with source documentation. – ysf Jun 16 '20 at 16:36
-1

function range(firstNum, lastNum) {
  let rangeList = [];
  if (firstNum > lastNum) {
    return console.error("First number cannot be bigger than last number");
  }

  let counter = firstNum;
  while(counter <= lastNum) {
    rangeList.push(counter);
    counter++;
  }

  return rangeList;
}
-1

nope - still no native javascript range in 2002, but this concise ES6 arrow-function can provide ascending and descending numbers and strings just like PHP (including steps).

// @return ascending or descending range of numbers or strings
const range = (a,b,d=1) => typeof a === 'string'
        ? range(a.charCodeAt(),b.charCodeAt()).map(v=>String.fromCharCode(v))
        : isNaN(b)
            ? range(0, a-1)
            : b < a
                ? range(b, a, d).reverse()
                : d > 1
                    ? range(a, b).filter(v => v%d === 0)
                    : [a,b].reduce((min,max)=>Array(max+1-min).fill(min).map((v,i)=>v+i));

// Usage
console.assert(
    range(3).toString() === '0,1,2' &&
    range(2,4).toString() === '2,3,4' && 
    range(4,2).toString() === '4,3,2' &&
    range(5,15,5).toString() === '5,10,15' && 
    range('A','C').toString() === 'A,B,C' && 
    range('C','A').toString() === 'C,B,A'
);
Ian Carter
  • 548
  • 8
  • 7
-3
function check(){

    var correct=true;

    for(var i=0; i<arguments.length; i++){

    if(typeof arguments[i] != "number"){

    correct=false;  } } return correct; }   

//------------------------------------------

 function range(start,step,end){

  var correct=check(start,step,end);

  if(correct && (step && end)!=0){ 

  for(var i=start; i<=end; i+=step)

  document.write(i+" "); }

  else document.write("Not Correct Data"); }
alex
  • 479,566
  • 201
  • 878
  • 984
george
  • 9
  • 1
    1. Your `check()` missed a chance to short circuit and early return, 2. You have a few redundant variables, 3. Using `document.write()` makes the function pretty useless for most applications – alex Aug 23 '15 at 23:35
  • Too long. Most of the solutions presented are extremely short and elegant. –  Nov 28 '20 at 14:19
-5

Loop over a range of numbers between 0 and your Length in Vue:


<div v-for="index in range" />

computed: {
   range () {
        let x = [];

        for (let i = 0; i < this.myLength; i++)
        {
            x.push(i);
        }

        return x;
    }
}
    
Dazzle
  • 2,880
  • 3
  • 25
  • 52
  • 1
    For such an old post, you need to include some commentary on why your answer is superior to the other 69 answers on this topic. Code-Only is simply not acceptable for posts like these, how is any user supposed to pick yours out of all that? – Chris Schaller Aug 23 '21 at 15:17
  • It's 2021 and this thread is full of totally overcomplicated ways of achieving this basic operation. Some users like me would like to see something easy to understand. Updated my code to give context to vue users – Dazzle Aug 23 '21 at 16:19
  • OP doesn't even say anything about using Vue. – MEMark Sep 01 '21 at 10:00
  • Welcome to 2021 – Dazzle Sep 01 '21 at 13:21