2
votes

I was just starting with codewars challenges, one of them is "Generate range of integers" problem. I managed to solve problem with for loop, but i was wondering if i could solve this problem in one line?

I have tried using fill and map methods combined with while and do-while loops. The problem is I am unable get the first number (starting min) inside my returned array. The first time while loop evaluates to true, it returns minimum incremented by step value.

function generateRange(min,max,step) {
        return Array(Math.floor((max - min) / step ))
                    .fill()
                    .map(() => {while(min <= max) {return min+=step;}});
    }
    
console.log(generateRange(0, 10, 2));

I was expecting number from min to max, with step within them. min = 0, max = 10, step = 2, result => [0,2,4,6,8,10] but i get all the numbers without the first starting minimum [2,4,6,8,10].

6
why is there a while loop inside of the map call. Make no sense - epascarello
You are going to have an off by one error with your logic since you are including the start and end. - epascarello

6 Answers

4
votes

You could decrement min by one step and take this value for further mapping.

function generateRange(min, max, step) {
    return Array.from(
        { length: Math.floor((max - (min -= step)) / step) },
        () => min += step
    );
}

console.log(generateRange(0, 10, 2));
2
votes

Sticking close to your original code:

function generateRange(min,max,step) {
return Array(Math.floor((max - min + step) / step ))
             .fill()
             .map(() => {while(min <= max) {return (min+=step)-step;}});
}
console.log(generateRange(0, 10, 2));
1
votes

function generateRange(min, max, step) {
  return "0".repeat(Math.floor((max - min) / step) + 1).split("").map((x, i) => min + i * step);
}

console.log(generateRange(0, 10, 2));
1
votes

Something like this should work:

function range(min,max,step = 1) {
   return [...Array(Math.floor((max-min+step)/step)).keys()].map(x => x*step + min);
}

console.log(range(0,10,2))
console.log(range(2,5,1))
console.log(range(1,25,5))
console.log(range(0,100,10))
1
votes

I think generator functions are nice for these type of things.

Your question asks for a one-liner, although I think it looks way nicer as 2 functions. This is because you could use the generator in other places that you might not require an array.

function* iter_generateRange(min,max,step) {
  for (let l = min; l <= max; l += step) yield l;
}

function generateRange(...args) {
 return Array.from(iter_generateRange(...args));
}

const generateRange1liner = (min, max, step) =>
  [...(function* () {
    for (let l = min; l <= max; l += step) yield l;
  }())]; 


//use the generateRange that returns the array
console.log(JSON.stringify(generateRange(10, 20, 2)));

//we can use it here too..
for (const r of iter_generateRange(3, 9, 3)) console.log(r);

//and finally using the 1 liner version
console.log(JSON.stringify(generateRange1liner(10, 20, 2)));
1
votes

This should work:

function generateRange(min,max,step) {
  return Array.from(Array(((max - min) / step) + 1).keys()).map(el => (el * step) + min);
}
console.log(generateRange(20, 40, 2));