Reputation: 2733
Say I have the following checkbox:
<input type="checkbox" value="1-25" />
To get the two numbers that define the boundaries of range I'm looking for, I use the following jQuery:
var value = $(this).val();
var lowEnd = Number(value.split('-')[0]);
var highEnd = Number(value.split('-')[1]);
How do I then create an array that contains all integers between lowEnd
and highEnd
, including lowEnd
and highEnd
themselves? For this specific example, obviously, the resulting array would be:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
Upvotes: 252
Views: 413365
Reputation: 36098
An elegant and versatile way to handle this is to create a generator:
/**
* Generates a range of numbers from start to end inclusively.
*/
function* range(start: number, end: number) {
for (let value = start; value <= end; value += 1) {
yield value;
}
}
Then you can use the spread operator on it:
[...range(30, 275)].map(value => `${value} cm`)
The function*
syntax denotes a generator which can pause execution and resume from where it left off. It allows it to produce a sequence of values over time instead of computing them all at once and returning them.
Upvotes: 1
Reputation: 955
After testing and adjusting all the pure js solutions above, I offer you the following solution, based on the fastest algo offered, and compatible with the python range.
The js version is even better, since it supports decimals.
function range(start, end, step=1) {
if (typeof end === 'undefined') {
end = start, start = 0;
}
let len = Math.round((end - start) / step);
let arr = [];
while ( len-- ) {
arr[len] = start + (len * step);
}
return arr;
}
console.log(range(9, 18, 0.83));
/* [
9,
9.83,
10.66,
11.49,
12.32,
13.149999999999999,
13.98,
14.809999999999999,
15.64,
16.47,
17.299999999999997
] */
console.log(range(9, 18, 2)); // [9, 11, 13, 15, 17]
console.log(range(9, 18)); // [9, 10, 11, 12, 13, 14, 15, 16, 17]
console.log(range(9)); // [0, 1, 2, 3, 4, 5, 6, 7, 8]
see the python code, for integers only:
print(list(range(9, 18, 2))); # [9, 11, 13, 15, 17]
print(list(range(9, 18))); # [9, 10, 11, 12, 13, 14, 15, 16, 17]
print(list(range(9))); # [0, 1, 2, 3, 4, 5, 6, 7, 8]
Upvotes: -1
Reputation: 3536
You can do that in one line in ES6
const start = 5; // starting number
const end = 10; // ending number
const arr = Array.from({ length: end - start + 1 }, (_, i) => start + i);
console.log(arr); // [5, 6, 7, 8, 9, 10]
Upvotes: 1
Reputation: 339
Typescript version:
function getAllNumbersBetween(start: number, end: number) {
var numbers: number[] = [];
for (var i = start; i < end; i++) {
numbers.push(i);
}
return numbers;
}
Upvotes: 1
Reputation: 764
Here's 3 functions that should cover everything I could think of (including fixes for problems in some other answers): rangeInt()
, range()
, and between()
. Both ascending and descending orders are accounted for in all cases.
rangeInt()
Includes endpoints and only deals with integers
rangeInt(1, 4) // [1, 2, 3, 4] Ascending order
rangeInt(5, 2) // [5, 4, 3, 2] Descending order
rangeInt(4, 4) // [4] Singleton set (i.e. not [4, 4])
rangeInt(-1, 1) // [-1, 0, 1] Mixing positive and negative
range()
Same as rangeInt()
except
range(0, 10, 2) // [0, 3.333, 6.666, 10] Gets endpoints and 2 points between
range(0, 1.5, 1) // [0, 0.75, 1.5] Accepts fractions
between()
Same as range()
except
between(0, 10, 2) // [3.333, 6.666]
between(-1, -1.5) // [-1.25]
between(4, 4, 99) // []
/**
* Gets a set of integers that are evenly distributed along a closed interval
* @param {int} begin - Beginning endpoint (inclusive)
* @param {int} end - Ending endpoint (inclusive)
* @return {Array} Range of integers
*/
function rangeInt( begin, end ) {
if ( !Number.isInteger(begin) || !Number.isInteger(end) ) {
throw new Error('All arguments must be integers')
}
return range(begin, end, Math.abs(end - begin) - 1)
}
/**
* Gets a set of numbers that are evenly distributed along a closed interval
* @param {Number} begin - Beginning endpoint (inclusive)
* @param {Number} end - Ending endpoint (inclusive)
* @param {int} points - How many numbers to retrieve from the open interval
* @return {Array} Range of numbers
*/
function range( begin, end, points ) {
if ( begin !== end ) {
return [ begin, ...between(begin, end, points), end ]
}
else if ( Number.isFinite(begin) ) {
return [ begin ] // singleton set
}
else throw new Error('Endpoints must be finite')
}
/**
* Gets a subset of numbers that are evenly distributed along an open interval
* @param {Number} begin - Beginning endpoint (exclusive)
* @param {Number} end - Ending endpoint (exclusive)
* @param {int} points - How many numbers to retrieve from the interval
* @return {Array} Retrieved numbers
*/
function between( begin, end, points = 1 ) {
if ( !Number.isFinite(begin) || !Number.isFinite(end) || !Number.isFinite(points) ) {
throw new Error('All arguments must be finite')
}
const set = []
// Skip if an open interval does not exist
if ( begin !== end ) {
const step = (end - begin) / (points + 1)
for ( let i = 0; i < points; i++ ) {
set[i] = begin + (i + 1) * step
}
}
return set
}
Upvotes: 3
Reputation: 117
Hope the below method will help someone.
Here count
variable can be used to mention the array length.
const generateRandomArryOfNumbers = (min = 1, max = 100, count = 31) => {
return Array.from(new Array(count), () =>
Math.floor(Math.random() * (max - min + 1) + min)
);
};
Upvotes: 0
Reputation: 277
const range = (start: number, end: number) => {
for (var i = start, list = []; i <= end; list.push(i), i++);
return list;
};
Upvotes: 0
Reputation: 10336
Inspired by m59's answer above, but without the dependency on fill
:
const range = (start, stop) => Array.from({ length: stop - start + 1 }, (_, i) => start + i)
So you can use it like:
range(3,5)
=> [3, 4, 5]
Upvotes: 9
Reputation: 1
_Array = (length) => Object.keys(Array.from({length}))
//_Array = [0, 1, 2, 3, 4]
Upvotes: -1
Reputation: 2648
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from
Upvotes: 1
Reputation: 93233
Use Array.from (docs here):
console.log(
Array.from({length:5},(v,k)=>k+1)
)
Upvotes: 184
Reputation: 15669
I highly recommend underscore or lo-dash libraries:
http://underscorejs.org/#range
(Almost completely compatible, apparently lodash runs quicker but underscore has better doco IMHO)
_.range([start], stop, [step])
Both libraries have bunch of very useful utilities.
Upvotes: 51
Reputation: 17551
My five cents:
Both direction array of integers function.
When range(0, 5) become [0, 1, 2, 3, 4, 5]
.
And range(5, 0) become [5, 4, 3, 2, 1, 0]
.
Based on this answer.
function range(start, end) {
const isReverse = (start > end);
const targetLength = isReverse ? (start - end) + 1 : (end - start ) + 1;
const arr = new Array(targetLength);
const b = Array.apply(null, arr);
const result = b.map((discard, n) => {
return (isReverse) ? n + end : n + start;
});
return (isReverse) ? result.reverse() : result;
}
P.S. For use in real life you should also check args for isFinite()
and isNaN()
.
Upvotes: 8
Reputation: 5645
function range(j, k) {
return Array
.apply(null, Array((k - j) + 1))
.map(function(_, n){ return n + j; });
}
this is roughly equivalent to
function range(j, k) {
var targetLength = (k - j) + 1;
var a = Array(targetLength);
var b = Array.apply(null, a);
var c = b.map(function(_, n){ return n + j; });
return c;
}
breaking it down:
var targetLength = (k - j) + 1;
var a = Array(targetLength);
this creates a sparse matrix of the correct nominal length. Now the problem with a sparse matrix is that although it has the correct nominal length, it has no actual elements, so, for
j = 7, k = 13
console.log(a);
gives us
Array [ <7 empty slots> ]
Then
var b = Array.apply(null, a);
passes the sparse matrix as an argument list to the Array constructor, which produces a dense matrix of (actual) length targetLength, where all elements have undefined value. The first argument is the 'this' value for the the array constructor function execution context, and plays no role here, and so is null.
So now,
console.log(b);
yields
Array [ undefined, undefined, undefined, undefined, undefined, undefined, undefined ]
finally
var c = b.map(function(_, n){ return n + j; });
makes use of the fact that the Array.map function passes: 1. the value of the current element and 2. the index of the current element, to the map delegate/callback. The first argument is discarded, while the second can then be used to set the correct sequence value, after adjusting for the start offset.
So then
console.log(c);
yields
Array [ 7, 8, 9, 10, 11, 12, 13 ]
Upvotes: 11
Reputation: 43755
In JavaScript ES6:
function range(start, end) {
return Array(end - start + 1).fill().map((_, idx) => start + idx)
}
var result = range(9, 18); // [9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
console.log(result);
For completeness, here it is with an optional step
parameter.
function range(start, end, step = 1) {
const len = Math.floor((end - start) / step) + 1
return Array(len).fill().map((_, idx) => start + (idx * step))
}
var result = range(9, 18, 0.83);
console.log(result);
I would use range-inclusive
from npm in an actual project. It even supports backwards steps, so that's cool.
Upvotes: 139
Reputation: 7141
Adding http://minifiedjs.com/ to the list of answers :)
Code is similar to underscore and others:
var l123 = _.range(1, 4); // same as _(1, 2, 3)
var l0123 = _.range(3); // same as _(0, 1, 2)
var neg123 = _.range(-3, 0); // same as _(-3, -2, -1)
var empty = _.range(2,1); // same as _()
Docs here: http://minifiedjs.com/api/range.html
I use minified.js because it solves all my problems with low footprint and easy to understand syntax. For me, it is a replacement for jQuery, MustacheJS and Underscore/SugarJS in one framework.
Of course, it is not that popular as underscore. This might be a concern for some.
Minified was made available by Tim Jansen using the CC-0 (public domain) license.
Upvotes: 1
Reputation: 1
function getRange(a,b)
{
ar = new Array();
var y = a - b > 0 ? a - b : b - a;
for (i=1;i<y;i++)
{
ar.push(i+b);
}
return ar;
}
Upvotes: -1
Reputation: 8418
If the start is always less than the end, we can do:
function range(start, end) {
var myArray = [];
for (var i = start; i <= end; i += 1) {
myArray.push(i);
}
return myArray;
};
console.log(range(4, 12)); // → [4, 5, 6, 7, 8, 9, 10, 11, 12]
If we want to be able to take a third argument to be able to modify the step used to build the array, and to make it work even though the start is greater than the end:
function otherRange(start, end, step) {
otherArray = [];
if (step == undefined) {
step = 1;
};
if (step > 0) {
for (var i = start; i <= end; i += step) {
otherArray.push(i);
}
} else {
for (var i = start; i >= end; i += step) {
otherArray.push(i);
}
};
return otherArray;
};
console.log(otherRange(10, 0, -2)); // → [10, 8, 6, 4, 2, 0]
console.log(otherRange(10, 15)); // → [10, 11, 12, 13, 14, 15]
console.log(otherRange(10, 20, 2)); // → [10, 12, 14, 16, 18, 20]
This way the function accepts positive and negative steps and if no step is given, it defaults to 1.
Upvotes: 6
Reputation: 1960
Solving in underscore
data = [];
_.times( highEnd, function( n ){ data.push( lowEnd ++ ) } );
Upvotes: -1
Reputation: 16706
fastest way
function:
var x=function(a,b,c,d){d=[];c=b-a+1;while(c--){d[c]=b--}return d},
theArray=x(lowEnd,highEnd);
or
var arr=[],c=highEnd-lowEnd+1;
while(c--){arr[c]=highEnd--}
EDIT
readable version
var arr = [],
c = highEnd - lowEnd + 1;
while ( c-- ) {
arr[c] = highEnd--
}
Demo
FOR THE DOWNVOTERS
performance
http://jsperf.com/for-push-while-set/2
faster in ie and 3x faster in firefox
only on aipad air the for loop is a little faster.
tested on win8, osx10.8, ubuntu14.04, ipad, ipad air, ipod;
with chrome,ff,ie,safari,mobile safari.
i would like to see the performance on older ie browsers where the for loop isn't that optimized!
Upvotes: 26
Reputation: 104780
You can design a range method that increments a 'from' number by a desired amount until it reaches a 'to' number. This example will 'count' up or down, depending on whether from is larger or smaller than to.
Array.range= function(from, to, step){
if(typeof from== 'number'){
var A= [from];
step= typeof step== 'number'? Math.abs(step):1;
if(from> to){
while((from -= step)>= to) A.push(from);
}
else{
while((from += step)<= to) A.push(from);
}
return A;
}
}
If you ever want to step by a decimal amount : Array.range(0,1,.01) you will need to truncate the values of any floating point imprecision. Otherwise you will return numbers like 0.060000000000000005 instead of .06.
This adds a little overhead to the other version, but works correctly for integer or decimal steps.
Array.range= function(from, to, step, prec){
if(typeof from== 'number'){
var A= [from];
step= typeof step== 'number'? Math.abs(step):1;
if(!prec){
prec= (from+step)%1? String((from+step)%1).length+1:0;
}
if(from> to){
while(+(from -= step).toFixed(prec)>= to) A.push(+from.toFixed(prec));
}
else{
while(+(from += step).toFixed(prec)<= to) A.push(+from.toFixed(prec));
}
return A;
}
}
Upvotes: 3
Reputation: 8269
My version of the loop ;)
var lowEnd = 1;
var highEnd = 25;
var arr = [];
while(lowEnd <= highEnd){
arr.push(lowEnd++);
}
Upvotes: 35
Reputation: 33993
function createNumberArray(lowEnd, highEnd) {
var start = lowEnd;
var array = [start];
while (start < highEnd) {
array.push(start);
start++;
}
}
Upvotes: 6
Reputation: 10104
var list = [];
for (var i = lowEnd; i <= highEnd; i++) {
list.push(i);
}
Upvotes: 249
Reputation: 42496
var values = $(this).val().split('-'),
i = +values[0],
l = +values[1],
range = [];
while (i < l) {
range[range.length] = i;
i += 1;
}
range[range.length] = l;
There's probably a DRYer way to do the loop, but that's the basic idea.
Upvotes: 3