JS data transformation methods don't seem to be working - javascript

Create a function 'calcAverageHumanAge', which accepts an arrays of dog's
ages ('ages'), and does the following things in order:
Calculate the dog age in human years using the following formula: if the dog is
<= 2 years old, humanAge = 2 * dogAge. If the dog is > 2 years old,
humanAge = 16 + dogAge * 4
Exclude all dogs that are less than 18 human years old (which is the same as
keeping dogs that are at least 18 years old)
Calculate the average human age of all adult dogs (you should already know
from other challenges how we calculate averages )
Run the function for both test datasets
Test data:
Data 1: [5, 2, 4, 1, 15, 8, 3]
Data 2: [16, 6, 10, 5, 6, 1, 4]
My solution(idk why wont work):
const calcAverageHumanAge = function (ageList) {
const avgAge = ageList
.map(val => (val <= 2 ? 2 * val : 16 + val * 4))
.fliter(val => val >= 18)
.reduce((acc, val, i, list) => {
return acc + val / list.length;
}, 0);};

You have three issues. Your reduce doesn't return anything is the main problem, but you're also dividing by list.length in each callback which doesn't make any sense (actually it does and I'm dumb), and then you aren't returning anything from the function. You want something like this:
const calcAverageHumanAge = function (ageList) {
const filteredVals = ageList
.map(val => (val <= 2 ? 2 * val : 16 + val * 4))
.filter(val => val >= 18);
return filteredVals.reduce((acc, val) => acc + val) / filteredVals.length;
};
When run on your data:
calcAverageHumanAge([5, 2, 4, 1, 15, 8, 3]); // 44
calcAverageHumanAge([16, 6, 10, 5, 6, 1, 4]); // 47.333

Related

Splitting an array into equal chunks and then allot remaining

I have a array where I need to divide equally into person number of chunks.
if there are 100 items in array for 10 persons, 10 chunks to be created with each 10 items
if there are 100 items in array for 9 persons, 9 chunks to be created and each would get 9 items and the extra should be given to first person, second person and so on. which means Person 1 = 10; Person 2, 3, 4 ... would have 9 items
if there are 100 items in array for 11 persons, 11 chunks are to be created with each would get 10 and the extra should be given to first person. which means
Person 1 is 10
Person 2 is 9
Person 3 is 9
Person 4 is 9
Person 5 is 9
Person 6 is 9
Person 7 is 9
Person 8 is 9
Person 9 is 9
Person 10 is 9
Person 11 is 9
I have tried with
Object.defineProperty(Array.prototype, 'chunk', {
value: function(chunkSize) {
var array = this;
return [].concat.apply([],
array.map(function(elem, i) {
return i % chunkSize ? [] : [array.slice(i, i + chunkSize)];
})
);
}
});
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ..., 150, 151].chunk(Math.floor(151 / 31))
but that would gives me an incorrect allocation.
Use the remainder of the division to get the number of slices that need an extra element. Then use the index in the new (chunked) array to determine whether it needs that extra element (i.e. when that index is less than the remainder).
NB: I would not alter the Array prototype. Just make this a plain function.
Implementation:
function partition(arr, length) {
let rest = arr.length % length;
let size = Math.floor(arr.length / length);
let j = 0;
return Array.from({length}, (_, i) => arr.slice(j, j += size + (i < rest)));
}
let data = Array.from({length: 151}, (_,i) => i+1);
let result = partition(data, 31);
console.log(result);
You can use generators to split an array in chunk:
function* chunks(arr, n) {
for (let i = 0; i < arr.length; i += n) {
yield arr.slice(i, i + n);
}
}
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ..., 150, 151];
console.log([...chunks(a, Math.floor(151 / 31))]);
Then you can adapt this code to move the last element in first place (if you want first person to be the most empty).
As a side note, you can replace this:
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ..., 150, 151];
with this:
let a = [...Array(151).keys()];

Dynamic Programming Bottoms up approach clarification [duplicate]

This question already has answers here:
What is the difference between bottom-up and top-down?
(9 answers)
Closed 1 year ago.
So I have been really trying to grasp Dynamic Programming. I can say that I really understand the memoization top down approach, but the bottoms up approach is really confusing to me. I was able to solve rods cutting top down, but I had to seek the solution for the bottoms up. I just don't understand when to use a 1D array or a 2D array. Then the for loop within the bottoms up is just confusing. Can anyone help me understand the differences in these two codes conceptually?
// Top Down Memoizaton:
const solveRodCuttingTop = function(lengths, prices, n) {
return solveRodCuttingHelper(0, lengths, prices, n);
};
function solveRodCuttingHelper(idx, span, prices, n, memo = []) {
// BASE CASES
if (idx === span.length || n <= 0 || prices.length !== span.length) {
return 0;
}
let included = 0, excluded = 0;
memo[idx] = memo[idx] || [];
if (memo[idx][n] !== undefined) return memo[idx][n];
if (span[idx] <= n) {
included = prices[idx] + solveRodCuttingHelper(idx, span, prices, n - span[idx], memo);
}
excluded = solveRodCuttingHelper(idx + 1, span, prices, n, memo);
memo[idx][n] = Math.max(included, excluded);
return memo[idx][n];
}
// Bottoms up
const solveRodCuttingBottom = function(lengths, prices, n) {
const rods = Array.from({length: n + 1});
rods[0] = 0;
let maxRevenue = - Infinity;
for (let i = 1; i < rods.length; i++) {
for (let j = 1; j <= i; j++) {
maxRevenue = Math.max(maxRevenue, prices[j - 1] + rods[i - j])
}
rods[i] = maxRevenue
}
return rods[prices.length];
};
const lengths = [1, 2, 3, 4, 5];
const prices = [2, 6, 7, 10, 13];
This is an interesting problem. Maybe I'm over-simplifying it, but if you first calculate each price per length, you can determine the solution by selling as much as possible at the highest rate. If the remaining rod is too short to sell at the best rate, move onto the next best rate and continue.
To solve using this technique, we first implement a createMarket function which takes lenghts and prices as input, and calculates a price-per-length rate. Finally the market is sorted by rate in descending order -
const createMarket = (lengths, prices) =>
lengths.map((l, i) => ({
length: l, // length
price: prices[i], // price
rate: prices[i] / l // price per length
}))
.sort((a, b) => b.rate - a.rate) // sort by price desc
const lengths = [1, 2, 3, 4, 5]
const prices = [2, 6, 7, 10, 13]
console.log(createMarket(lengths, prices))
[
{ length: 2, price: 6, rate: 3 },
{ length: 5, price: 13, rate: 2.6 },
{ length: 4, price: 10, rate: 2.5 },
{ length: 3, price: 7, rate: 2.3333333333333335 },
{ length: 1, price: 2, rate: 2 }
]
Next we write recursive solve to accept a market, [m, ...more], and a rod to cut and sell. The solution, sln, defaults to [] -
const solve = ([m, ...more], rod, sln = []) =>
m == null
? sln
: m.length > rod
? solve(more, rod, sln)
: solve([m, ...more], rod - m.length, [m, ...sln])
const result =
solve(createMarket(lengths, prices), 11)
console.log(result)
[
{ length: 1, price: 2, rate: 2 },
{ length: 2, price: 6, rate: 3 },
{ length: 2, price: 6, rate: 3 },
{ length: 2, price: 6, rate: 3 },
{ length: 2, price: 6, rate: 3 },
{ length: 2, price: 6, rate: 3 }
]
Above, solve returns the rod lengths that sum to the maximum price. If you want the total price, we can reduce the result and sum by price -
const bestPrice =
solve(createMarket(lengths, prices), 11)
.reduce((sum, r) => sum + r.price, 0)
console.log(bestPrice)
32

how to split an array into equal chunks?

I've found a lot of answers to the question "how to split an array in multiple chunks", but I can't find a way to best repartition the array. For example,
let x = [1,2,3,4,5,6,7,8,9,10,11,12,13];
//#Source https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-265.php
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
const n = 10;
console.log(chunk(x,n))
This function gives me two arrays: [1,2,3,4,5,6,7,8,9,10] and [11,12,13]. But I would prefere n to be used as a "max" to obtain [1,2,3,4,5,6,7] and [8,9,10,11,12,13]. This way I would have two arrays of the same size. If it is possible for the selected n, they should be of equal size, otherwise, two arrays with a nearly identical size.
I broke it down into 3 steps.
Compute numChunks, how many chunks you need? E.g. if you have an array of 103 elements and a max size of 10, then you'll need 11 chunks.
Compute minChunkSize, the size of the smaller chunks. E.g. in the above example, the first 7 chunks will have 10 elements, while the other 3 chunks will have 11 elements (710 + 311 = 103).
Compute numSmallChunks, how many small chunks you can have. E.g. 3 in the above example.
Then you just splice the arr accordingly.
let chunk = (arr, maxSize) => {
let numChunks = parseInt((arr.length - 1) / maxSize) + 1;
let minChunkSize = parseInt(arr.length / numChunks);
let numSmallChunks = numChunks * (minChunkSize + 1) - arr.length;
arr = [...arr]; // avoid muckking the input
let arrays = [];
for (let i = 0; i < numChunks; i++)
if (i < numSmallChunks)
arrays.push(arr.splice(0, minChunkSize));
else
arrays.push(arr.splice(0, minChunkSize + 1));
return arrays;
};
let x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
for (let i = 1; i < x.length; i++)
console.log(i, JSON.stringify(chunk(x, i), null, ''));
Note, the other answers result in an unbalanced; e.g. they produce arrays of sizes 4, 4, 4, & 1 when n is 4. Whereas my approach produces arrays of sizes 3, 3, 3, & 4. I guess it's up to the situation which you need, but this is how I interpret the question's "equal chunks".
If you need n to be max, Then calculate size as below.
let x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
const chunk = (arr, max) => {
const size = Math.min(max, Math.ceil(arr.length / 2));
return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
};
const n = 10;
console.log(chunk(x, n));
You could slice with a variable size.
1 2 3 4 5 5
6 7 8 9 10 5
11 12 13 14 4
15 16 17 18 4
const
chunk = (array, max) => {
let
length = Math.ceil(array.length / max),
size = Math.ceil(array.length / length);
return Array.from(
{ length },
(_, i) => (
array.length === size * length - length + i && size--,
array.slice(size * i, size * (i + 1))
)
);
}
console.log(chunk([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], 5).map(a => a.join(' ')));

How to iterate over an array multiple times without repeating summed elements

I am trying to solve this problem but I don't know why I can't pass all test cases. I need some help and explanation, how can I count some array (in this example: variable s) multiple times and not repeat the same elements that I already summed.
Problem description:
Lily has a chocolate bar that she wants to share it with Ron for his
birthday. Each of the squares has an integer on it. She decides to
share a contiguous segment of the bar selected such that the length of
the segment matches Ron's birth month and the sum of the integers on
the squares is equal to his birth day. You must determine how many
ways she can divide the chocolate.
Consider the chocolate bar as an array of squares, s=[2,2,1,3,2].
She wants to find segments summing to Ron's birth day, d=4 with a
length equalling his birth month, m=2. In this case, there are two
segments meeting her criteria: [2,2] and [1,3].
Function Description
Complete the birthday function in the editor below. It should return
an integer denoting the number of ways Lily can divide the chocolate
bar.
birthday has the following parameter(s):
s: an array of integers, the numbers on each of the squares of
chocolate,
d: an integer, Ron's birth day, m: an integer, Ron's birth month
My code:
function birthday(s, d, m) {
let bars = 0;
if (m !== 1) {
s.reduce((acc, val) => (acc+val) === d ? ++bars : bars)
} else {
bars = 1;
}
return bars;
}
Some cases:
s = [2, 5, 1, 3, 4, 4, 3, 5, 1, 1, 2, 1, 4, 1, 3, 3, 4, 2, 1]
d = 18
m = 7
s = [4, 5, 4, 5, 1, 2, 1, 4, 3, 2, 4, 4, 3, 5, 2, 2, 5, 4, 3, 2, 3,
5, 2, 1, 5, 2, 3, 1, 2, 3, 3, 1, 2, 5]
d = 18
m = 6
s = [4, 5, 4, 2, 4, 5, 2, 3, 2, 1, 1, 5, 4]
d = 15
m = 4
My code works with this:
s = [1, 2, 1, 3, 2]
d = 3
m = 2
This can be found on HackerRank > Practice > Algorithms > Implementation
You just have to slice the array with the sliced length of m, and then compare that to d
As slice doc:
The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified.
For example:
s = [1, 2, 1, 3, 2]
m = 2
d = 3
// We loop through s with index stop at s.length - m + 1 for slice to be in correct range
// Slices:
i=0: [1, 2] -> sum=3 -> res=0+1=1
i=1: [2, 1] -> sum=3 -> res=1+1=2
i=2: [1, 3] -> sum=4 -> do nothing
i=4: [3, 2] -> sum=5 -> do nothing
Below is a worked solution
function birthday(s, d, m) {
let res = 0
const sum = (arr) => arr.reduce((acc, el) => acc + el, 0)
for (let i = 0; i < s.length - m + 1; i++) {
if (sum(s.slice(i, i + m)) === d) {
res++
}
}
return res
}
Whenever you are looping over an array to get the summation or do a mathematical equation on it and you have to remove that specific element that you already calculated, You can use one of these built in function to remove an element from an array using a specific index.
Array.prototype.slice()
&& Array.prototype.splice()
Here's an easy to understand way with nested loops:
function birthday(s, d, m) {
var matches = 0; // Total matches found
// Look at chunks starting a position 0. Last chunk can't be m spots past end of array, so last chunk starts at 1 + s.length - m:
for ( let i=0; i < 1 + s.length - m; i++ ) {
var sum = 0; // What this chunk sums to
// Sum up the values of this chunk:
for ( let j=0; j < m; j++ ) {
sum += s[i+j];
}
if ( sum === d ) { // Does this chunk sum to d?
matches++; // Yes!
}
}
return matches;
}

Is there a JS function that acts like IntStream in Java? [duplicate]

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?
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)
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
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))
Here's my 2 cents:
function range(start, end) {
return Array.apply(0, Array(end - 1))
.map((element, index) => index + start);
}
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));
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;
}
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"]
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']
https://stackoverflow.com/a/49577331/8784402
With Delta/Step
smallest and one-liner
[...Array(N)].map((_, i) => from + i * step);
Examples and other alternatives
[...Array(10)].map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10)).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array.from(Array(10).keys()).map(i => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
[...Array(10).keys()].map(i => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Array(10).fill(0).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
Array(10).fill().map((_, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
Range Function
const range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
range(0, 9, 2);
//=> [0, 2, 4, 6, 8]
// can also assign range function as static method in Array class (but not recommended )
Array.range = (from, to, step) =>
[...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);
Array.range(2, 10, 2);
//=> [2, 4, 6, 8, 10]
Array.range(0, 10, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.range(2, 10, -1);
//=> []
Array.range(3, 0, -1);
//=> [3, 2, 1, 0]
As Iterators
class Range {
constructor(total = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
for (let i = 0; i < total; yield from + i++ * step) {}
};
}
}
[...new Range(5)]; // Five Elements
//=> [0, 1, 2, 3, 4]
[...new Range(5, 2)]; // Five Elements With Step 2
//=> [0, 2, 4, 6, 8]
[...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
//=>[10, 8, 6, 4, 2]
[...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of new Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
As Generators Only
const Range = function* (total = 0, step = 1, from = 0) {
for (let i = 0; i < total; yield from + i++ * step) {}
};
Array.from(Range(5, -2, -10));
//=> [-10, -12, -14, -16, -18]
[...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]
// Also works with for..of loop
for (i of Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
// Lazy loaded way
const number0toInf = Range(Infinity);
number0toInf.next().value;
//=> 0
number0toInf.next().value;
//=> 1
// ...
From-To with steps/delta
using iterators
class Range2 {
constructor(to = 0, step = 1, from = 0) {
this[Symbol.iterator] = function* () {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
}
}
[...new Range2(5)]; // First 5 Whole Numbers
//=> [0, 1, 2, 3, 4, 5]
[...new Range2(5, 2)]; // From 0 to 5 with step 2
//=> [0, 2, 4]
[...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
using Generators
const Range2 = function* (to = 0, step = 1, from = 0) {
let i = 0,
length = Math.floor((to - from) / step) + 1;
while (i < length) yield from + i++ * step;
};
[...Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
let even4to10 = Range2(10, 2, 4);
even4to10.next().value;
//=> 4
even4to10.next().value;
//=> 6
even4to10.next().value;
//=> 8
even4to10.next().value;
//=> 10
even4to10.next().value;
//=> undefined
For Typescript
class _Array<T> extends Array<T> {
static range(from: number, to: number, step: number): number[] {
return Array.from(Array(Math.floor((to - from) / step) + 1)).map(
(v, k) => from + k * step
);
}
}
_Array.range(0, 9, 1);
https://stackoverflow.com/a/64599169/8784402
Generate Character List with one-liner
const charList = (a,z,d=1)=>(a=a.charCodeAt(),z=z.charCodeAt(),[...Array(Math.floor((z-a)/d)+1)].map((_,i)=>String.fromCharCode(a+i*d)));
console.log("from A to G", charList('A', 'G'));
console.log("from A to Z with step/delta of 2", charList('A', 'Z', 2));
console.log("reverse order from Z to P", charList('Z', 'P', -1));
console.log("from 0 to 5", charList('0', '5', 1));
console.log("from 9 to 5", charList('9', '5', -1));
console.log("from 0 to 8 with step 2", charList('0', '8', 2));
console.log("from α to ω", charList('α', 'ω'));
console.log("Hindi characters from क to ह", charList('क', 'ह'));
console.log("Russian characters from А to Я", charList('А', 'Я'));
For TypeScript
const charList = (p: string, q: string, d = 1) => {
const a = p.charCodeAt(0),
z = q.charCodeAt(0);
return [...Array(Math.floor((z - a) / d) + 1)].map((_, i) =>
String.fromCharCode(a + i * d)
);
};
var range = (l,r) => new Array(r - l).fill().map((_,k) => k + l);
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
--- 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);
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 ]
If, on Visual Studio Code, you faced the error:
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
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);
}
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.
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
If you use Ramda, they have their own R.range as does Lodash
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]
Not implemented yet!
Using the new Number.range proposal (stage 1):
[...Number.range(1, 10)]
//=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
(from, to) => [...Array(to - from)].map((_,i)=> i + from)
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})}
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]
My personal favorite:
const range = (start, end) => new Array(end-start+1).fill().map((el, ind) => ind + start);
ES6
Use Array.from (docs here):
const range = (start, stop, step) => Array.from({ length: (stop - start) / step + 1}, (_, i) => start + (i * step));
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
);
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.
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]
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 ]
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.
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 ));
}

Categories