Does JavaScript have a method like "range()" to generate a range within the supplied bounds?
Asked Answered
V

93

1679

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?

Vanegas answered 9/10, 2010 at 2:37 Comment(11)
Prototype.js has the $R function, but other than that I don't really think so.Ostiole
This (related) question has some excellent answers: stackoverflow.com/questions/6299500/…Zanthoxylum
Array.from("ABC") //['A', 'B', 'C'] This is the closest thing I can find for the second part of the question.Whimsical
@Whimsical You could use split("") there alsoVanegas
When lover bound is zero this oneliner: Array.apply(null, { length: 10 }).map(eval.call, Number)Easygoing
See https://mcmap.net/q/20939/-how-to-create-an-array-containing-1-n -> Array.from({length: N}, (v, k) => k+1);Yarmouth
Possible duplicate of Create a JavaScript array containing 1...NElver
btw just for info there's a tc39 proposal for Number.range, which is stage-1 at the moment github.com/tc39/proposal-Number.rangeHowlond
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)' 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)Cochard
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.Tenne
Maybe helpfulCrescint
V
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));
Vanegas answered 9/10, 2010 at 2:54 Comment(0)
I
2688

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)

Isotope answered 7/4, 2012 at 1:5 Comment(22)
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)Ophir
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);});Helms
Useful Lodash function, but does not answer the second part of this question: how to create a character range.Misdirection
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.Reginareginald
@Reginareginald Because an array defined with that has empty slots that won't be iterated over with map() or one of its friends.Vanegas
Be aware that you cannot use Array.from in IE (but it probably works in Edge) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Unchain
You also can use the spread operator [...new Array(5)] , only working with modern browser or using transpiler (ES2015)Mismanage
The spread operator is already used in the ES6 example. [...new Array(5)] prints 5 undefined'sIsotope
Array(5).fill() is also mappableChibouk
Here's a worst way to achieve this: Array.apply(null, new Array(5)).map(Number.call.bind(Number))Tafilelt
Array.from(Array(5).keys()) is an ES6 alternative that works in typescript without the downlevelIteration compiler flag if anyone was lookingKoodoo
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;});Louvar
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://mcmap.net/q/20939/-how-to-create-an-array-containing-1-nKnuckleduster
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]Briar
Indeed Array(5).fill() is mappable, and preferable because is WAY more performant (~4x) than the spread of [...Array(5).keys()]Blackguard
If you have a downlevelIteration warning, see this answerTraprock
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)] incrementMinefield
@Minefield 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 optimizationIsotope
"As typed functions" Is this typescript or JavaScript?Foveola
It is incredible that a language as high-level and popular as JS still lacks a straightforward range or [:] syntax in 2023.Tenne
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.Tenne
fwiw, although all these alternatives will mimic range, they are not equivalent. If you needed a range from 1 to 1 billion, you would have to generate a billion element array or string in memory. Range/Enumerate/Dict.items/values all generate iterators that only spit out one number at a time, making them a whole lot more efficient when working with decently sized ranges.Throttle
N
619

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

Napoleonnapoleonic answered 10/4, 2015 at 10:47 Comment(9)
The first example can even be simplified to [...Array(20).keys()]Dabbs
Slightly more succinct than the Array.from() method, and faster than both: Array(20).fill().map((_, i) => i)Nippon
@Dabbs @jib And this as well: Array.from({length: end - start}, (v, k) => k + start)Reyna
Nifty if you'd like to create array of empty subarrays too (var matrix = Array.from(new Array(3), () => []);).Alisha
Some android devices (mainly Samsung) seem to be missing Array.from: Uncaught TypeError: Object function Array() { [native code] } has no method 'from'.Start
Your longer version is actually shorter if you remove the unneeded "new" before Array.Allison
@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.Nippon
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 undefineds, 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 itHarte
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.Tenne
A
264

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))
Arredondo answered 6/7, 2017 at 19:12 Comment(5)
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.Recency
Try this: Array(10).fill(1).map((x, i) => i)Dogbane
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)Traveler
FYI MDN 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));Harmonious
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.Tenne
M
111

Here's my 2 cents:

function range(start, end) {
  return Array.apply(0, Array(end - 1))
    .map((element, index) => index + start);
}
Mormon answered 21/10, 2013 at 22:51 Comment(3)
This is actually wrong because the question is asking for start & end values. Not start & count/distance.Dispensation
This answer does not work as expected. The output is not usable.Prong
it would work as expected, when Array(end - 1) is changed like Array(end - start + 1)Facility
V
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));
Vanegas answered 9/10, 2010 at 2:54 Comment(0)
L
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;
}
Lulualaba answered 16/3, 2013 at 19:10 Comment(3)
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; }Uuge
@Uuge I added a default step above, (step || 1).Amador
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.Gael
I
59

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"]
Inconvincible answered 27/7, 2017 at 15:46 Comment(1)
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).Mattress
S
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']
Strafford answered 9/10, 2010 at 3:42 Comment(3)
You really shouldn't jerry-rig methods onto the Array prototype.Enrich
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!Bowerman
As miike3459 wrote, if one day Array.range is added to standard lib you might have a serious problem.Sedimentation
B
46

https://mcmap.net/q/20940/-how-to-generate-range-of-numbers-from-0-to-n-in-es2015-only

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://mcmap.net/q/20941/-how-to-generate-an-array-of-the-alphabet

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)
  );
};
Bainite answered 1/11, 2020 at 1:48 Comment(1)
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.Tenne
C
31
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
Carhop answered 27/3, 2016 at 18:57 Comment(2)
Very neat! Although, it's important to note it doesn't work on any IE or Opera.Radiobroadcast
@RafaelXavier will work on IE with Array.fill() polyfillTorque
L
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
Lordship answered 13/8, 2015 at 13:20 Comment(0)
T
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);
Teutonize answered 28/5, 2017 at 17:46 Comment(0)
T
27

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

Traprock answered 3/9, 2021 at 14:0 Comment(0)
C
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 ]
Coronal answered 30/12, 2014 at 9:21 Comment(0)
B
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);
}
Bullfighter answered 11/7, 2015 at 13:20 Comment(3)
The ES6 part is now the correct answer to this question. I would recommend removing the other parts, which are covered by other answers.Thill
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 arrayToadstool
@Toadstool you can use Array.from to convert generators to array instances and inspect the output.Bullfighter
L
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.

Legpull answered 25/1, 2014 at 18:59 Comment(1)
Note that this was compared against range functions that included a step size parameterCasque
F
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

Frap answered 28/1, 2019 at 6:0 Comment(0)
L
16

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]
Logorrhea answered 18/11, 2020 at 6:32 Comment(0)
C
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]

Curarize answered 11/9, 2019 at 13:45 Comment(0)
A
14
(from, to) => [...Array(to - from)].map((_,i)=> i + from)
Autotrophic answered 9/11, 2021 at 15:17 Comment(0)
B
13

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)
))
Blackett answered 14/1, 2023 at 23:37 Comment(4)
This method only works if your range starts at 0.Feu
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.Blackett
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.Feu
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 ;).Blackett
A
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})}
Amery answered 6/8, 2014 at 17:24 Comment(2)
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 syntaxCadastre
@nafg: const range = (a, b, Δ = 1) => (a > b) ? [] : [a, ...range(a + Δ, b, Δ)];. Also upvoting the whole answer for the comment.Siena
G
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]
Godderd answered 28/8, 2015 at 13:26 Comment(0)
R
12

My personal favorite:

const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
Rohn answered 28/11, 2020 at 14:15 Comment(1)
maybe better [...Array(end-start+1)].map((el, ind) => ind + start); ?Butterscotch
H
12

ES6

Use Array.from (docs here):

const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
Harmonyharmotome answered 26/6, 2021 at 19:3 Comment(0)
N
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
);
Niemi answered 15/2, 2017 at 3:3 Comment(2)
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"]Niemi
you don't need the new keywordLobectomy
C
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.

Chuddar answered 9/10, 2010 at 2:53 Comment(4)
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 👍Tentmaker
@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 2018Chuddar
Well this didn't help at all.Cultivation
@Cultivation 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.Chuddar
C
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] 
Clari answered 9/7, 2014 at 13:6 Comment(1)
+1 for the fastest. with an array of -36768 - 36768, took 3ms, 2nd place was 13 ms and has IDE red lines.Nonintervention
T
9

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]
Triphylite answered 30/11, 2015 at 4:59 Comment(2)
I never knew D3 existed. Not going to use their range method but will be using this package.Nonintervention
Thank you so much. I use D3 and was looking for a native JS method, not knowing that I D3 offers it already.Wehrle
P
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 ]
Pleasurable answered 12/4, 2019 at 14:1 Comment(0)
L
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.

Lemons answered 22/5, 2015 at 16:47 Comment(4)
Setting array = [] inside the loop may not give you what you want.Vanegas
@alex, thank you. You're right, I also forgot to increment the "start" parameter on each pass of the loop. It's fixed now.Lemons
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.Vanegas
@alex, thank you again, I had not considered a length constraint based on input. See updated version.Lemons
V
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));
Vivia answered 22/7, 2019 at 16:26 Comment(0)
M
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 ));
}
Mosstrooper answered 2/1, 2021 at 14:51 Comment(0)
W
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"]

Wolframite answered 30/10, 2012 at 15:38 Comment(2)
Edited with my suggestions :)Ovipositor
+1 for the approach. To @alex's point, not having ternary operations (especially not nested) in the for clause would improve readability here.Dagmardagna
C
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.

Ciao answered 10/10, 2017 at 21:36 Comment(0)
U
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)
Uttermost answered 16/7, 2019 at 15:11 Comment(0)
J
5

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

Jaffe answered 2/2, 2015 at 15:47 Comment(0)
T
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

Toadstool answered 8/10, 2016 at 9:32 Comment(1)
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!Metalware
M
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]
Mylesmylitta answered 10/10, 2021 at 9:29 Comment(1)
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.Chronopher
T
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]
Taryn answered 16/11, 2021 at 21:58 Comment(1)
the external brackets can be removed safely: ` [...Array(10-3).keys()].map(i=>i+3) == [ 3, 4, 5, 6, 7, 8, 9 ] `Bon
B
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()));
Brainwork answered 13/10, 2016 at 16:2 Comment(1)
A slightly less greedy yet still concise alternative, Array(1 + upper - lower).fill().map((v, i) => i + lower)Brainwork
A
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.

Arbitration answered 13/2, 2018 at 3:51 Comment(0)
P
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].

Paring answered 17/6, 2022 at 22:49 Comment(0)
T
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]
Tumulus answered 7/7, 2022 at 3:43 Comment(0)
R
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;});
Rosalynrosalynd answered 9/10, 2015 at 20:50 Comment(1)
Use [...Array(e-b)] while you are at it.Disability
P
3

You can also do the following:

const range = Array.from(Array(size)).map((el, idx) => idx+1).slice(begin, end);
Peristome answered 23/7, 2018 at 1:12 Comment(0)
K
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]);
        })
    })
})
K answered 14/11, 2018 at 1:58 Comment(0)
D
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']
Dialectical answered 18/11, 2019 at 20:4 Comment(1)
quite smart solution with .fromCharCode().Pennywise
W
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);
}
Withal answered 26/11, 2019 at 18:6 Comment(0)
B
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))
Blackett answered 3/5, 2021 at 22:29 Comment(0)
G
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
}
Gaidano answered 30/11, 2021 at 8:33 Comment(2)
Interesting way of making the iterator object reusable :)Riorsson
@Riorsson Thanks :)Gaidano
D
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 ]
Dropline answered 6/4, 2019 at 16:59 Comment(0)
M
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);
}   

Mischiefmaker answered 23/6, 2021 at 12:39 Comment(0)
S
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 ]
Span answered 17/5, 2022 at 20:25 Comment(1)
For others info, usage og generateRange here: for (let i of generateRange(5,10)){console.log(i)}Boylston
I
2

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

Ianthe answered 2/12, 2022 at 5:49 Comment(0)
G
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};
Gurule answered 7/6, 2014 at 10:24 Comment(0)
P
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]
Petrinapetrine answered 31/7, 2014 at 17:42 Comment(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.Vanegas
G
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]
Girardo answered 7/11, 2015 at 9:42 Comment(0)
U
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
Uturn answered 21/9, 2019 at 9:19 Comment(0)
D
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.

Diagnosis answered 10/10, 2019 at 1:54 Comment(0)
B
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
Bowerman answered 4/12, 2019 at 7:5 Comment(8)
It's unwise to modify any built-in objects such as ArrayHose
@JonKoops Can you explain why?Bowerman
flaviocopes.com/javascript-why-not-modify-object-prototypeHose
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.Bowerman
I understand, however that is still not an ideal solution. If any browser vendor ever implements this API this code will simply stop working.Hose
@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.Bowerman
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.Hose
Additional check for typeof from === typeof toBuckram
O
1

Pythonic styled way:

range = (start, end, step) => {
let arr = []
for(let n=start;n<end;n+=(step||1)) arr.push(n)
return arr;
}
Owner answered 23/5, 2020 at 17:18 Comment(0)
K
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));
Kathe answered 21/9, 2020 at 2:6 Comment(0)
U
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]
Uganda answered 10/12, 2021 at 1:4 Comment(0)
L
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]
Lila answered 1/2, 2023 at 11:40 Comment(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 iteratorCorneille
M
1

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));
Marinna answered 30/3, 2023 at 8:53 Comment(0)
C
1

If you need a "Large Range". For speed you can use TypedArray:

// Fast Range with TypedArray:
Object.getPrototypeOf(Uint8Array).Range=function(start,stop,step=1){
    if(stop==null){stop=start;start=0;}
    let l=Math.ceil((stop-start)/step),arr=new this(l);
    for(let i=0;i<l;i++)arr[i]=start+i*step;
    return arr};

// Usage:
let rangeA=Uint8Array.Range(5);
let rangeB=Int16Array.Range(-250,250,100);
let rangeC=Float64Array.Range(0,.5,.1);
console.log(rangeA,rangeB,rangeC);

TypedArray Info:

Int8Array           -128 to 127
Uint8Array          0 to 255
Uint8ClampedArray   0 to 255
Int16Array          -32768 to 32767
Uint16Array         0 to 65535
Int32Array          -2147483648 to 2147483647
Uint32Array         0 to 4294967295
Float32Array        -3.4e38 to 3.4e38
Float64Array        -1.8e308 to 1.8e308
BigInt64Array       -2**63 to 2**63-1
BigUint64Array      0 to 2**64-1

Speed comparison:

Object.getPrototypeOf(Uint8Array).Range=function(start,stop,step=1){
    if(stop==null){stop=start;start=0;}
    let l=Math.ceil((stop-start)/step),arr=new this(l);
    for(let i=0;i<l;i++)arr[i]=start+i*step;
    return arr;};

Object.getPrototypeOf(Array).Range=function(start,stop,step=1){
    if(stop==null){stop=start;start=0;}
    let l=Math.ceil((stop-start)/step),arr=new this(l);
    for(let i=0;i<l;i++)arr[i]=start+i*step;
    return arr;};

// Speed comparison:
let rsize=10**8,range;

console.time('Array Range');
range=Array.Range(rsize);
console.timeEnd('Array Range'); // Array Range: 3008.181 ms

console.time('TypedArray Range');
range=Uint32Array.Range(rsize);
console.timeEnd('TypedArray Range'); // TypedArray Range: 256.283 ms

Or see on https://jsben.ch/uaEvH


If you need "Iterator":

let range=function*(start,stop,step=1){
    if(stop==null){stop=start;start=0;}
    let l=Math.ceil((stop-start)/step);
    for(let i=0;i<l;i++)yield start+i*step;
};

for(let i of range(4))console.log(i);

If you need "String Range":

String.Range=function(start,stop){
    if(stop==null){stop=start;start='a';}
    start=start.charCodeAt(0),stop=stop.charCodeAt(0);
    let l=stop-start+1,buffer=new ArrayBuffer(l),view=new Uint8Array(buffer);
    for(let i=0;i<l;i++)view[i]=start+i;
    return new TextDecoder("utf-8").decode(buffer);
};

console.log(String.Range('A','D')); // ABCD
Cohobate answered 22/12, 2023 at 15:23 Comment(0)
G
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
    });
}
Gorey answered 28/9, 2015 at 14:9 Comment(1)
Best performance has a few things that could be improved, such as setting step to a default value outside of the loop.Vanegas
O
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;
};
Oculus answered 20/10, 2015 at 22:12 Comment(1)
Does a lot of unnecessary work each iteration though.Vanegas
M
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;
}
Martyrize answered 4/3, 2016 at 16:34 Comment(3)
var highest = Math.max.apply(null, array).Vanegas
or Math.max(...array)Vanegas
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 hereThomas
J
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]
Jacqualinejacquard answered 24/3, 2016 at 23:1 Comment(0)
K
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"));
Killerdiller answered 21/12, 2016 at 20:4 Comment(0)
N
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.

Nonintervention answered 10/5, 2017 at 13:58 Comment(2)
Array.prototype.reverse() is expensive though for any decently long range.Vanegas
@Vanegas 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.Nonintervention
R
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);
Rawden answered 18/5, 2018 at 21:18 Comment(0)
B
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]
Beebeebe answered 26/12, 2018 at 18:2 Comment(0)
A
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

Aggappora answered 18/11, 2019 at 16:41 Comment(0)
L
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
Lauder answered 3/1, 2022 at 19:9 Comment(0)
M
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]
Manoeuvre answered 27/1, 2022 at 14:37 Comment(0)
G
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://mcmap.net/q/20881/-does-javascript-have-a-method-like-quot-range-quot-to-generate-a-range-within-the-supplied-bounds}
 */
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>
Gladstone answered 26/5, 2022 at 8:24 Comment(0)
H
0

A typescript function to closely replicate

/**
 * Create a generator from 0 to stop, useful for iteration. Similar to range in Python.
 * See: https://mcmap.net/q/20881/-does-javascript-have-a-method-like-quot-range-quot-to-generate-a-range-within-the-supplied-bounds
 * 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://mcmap.net/q/20881/-does-javascript-have-a-method-like-quot-range-quot-to-generate-a-range-within-the-supplied-bounds
 * 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://mcmap.net/q/20881/-does-javascript-have-a-method-like-quot-range-quot-to-generate-a-range-within-the-supplied-bounds
 * 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
  }
}
Hodeida answered 18/6, 2022 at 0:46 Comment(0)
O
0

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'
);
Oversew answered 14/10, 2022 at 2:12 Comment(1)
I just love your use of the word "concise" here!Errolerroll
B
0

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

[...Iterator.range(0, 5)]; // [0, 1, 2, 3, 4]
Bazemore answered 31/3, 2023 at 21:3 Comment(0)
A
0

const numStart = 1990;
const numEnd = 2020;
const numInRange = [...Array(numEnd - numStart + 1).keys()].map(i => i + numStart);
console.log(numInRange);
Astronautics answered 7/9, 2023 at 7:53 Comment(0)
A
0

Adding on to @fuji's answer, to set a lower bound, use .slice(lowerbound)

Abyss answered 5/12, 2023 at 2:32 Comment(0)
E
-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;
}
Euphemize answered 1/8, 2015 at 15:57 Comment(0)
S
-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]);
}
Soupy answered 13/9, 2015 at 19:31 Comment(1)
As @Zanthoxylum posted, there are many approaches in this related postChiropractor
R
-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']
Rusert answered 8/10, 2016 at 9:41 Comment(3)
You just reinvented array.slice(1,5).Undeviating
slice has a slight disadvantage of having side effect - modifying the passed array (which wouldnt harm in example above, but might in real life code)Shoemake
slice() does not modify the original array. Maybe you're thinking of splice().Vanegas
S
-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));
Sextain answered 24/7, 2017 at 7:17 Comment(1)
For the love of everything holy, please don't mess with Object.prototype. It causes more pain than it's worth.Talipes
G
-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);
Galahad answered 2/5, 2018 at 12:49 Comment(0)
H
-1
Array.from(Array((m - n + 1)), (v, i) => n + i); // m > n and both of them are integers.
Harter answered 16/6, 2020 at 12:36 Comment(1)
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.Sporogony
K
-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;
}
Kantor answered 6/11, 2021 at 15:30 Comment(1)
There are a lot of other answers here. What makes this different from the rest?Garrek
G
-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"); }
Gothenburg answered 21/8, 2015 at 12:6 Comment(2)
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 applicationsVanegas
Too long. Most of the solutions presented are extremely short and elegant.Rohn
S
-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;
    }
}
    
Stomach answered 23/8, 2021 at 12:16 Comment(4)
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?Marlanamarlane
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 usersStomach
OP doesn't even say anything about using Vue.Errolerroll
Welcome to 2021Stomach

© 2022 - 2024 — McMap. All rights reserved.