最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

making a range function in javascript - Stack Overflow

programmeradmin0浏览0评论

I am trying to make a function in javascript that returns an array from range(start,end) and im supposed to make an optional argument that defaults to one when it is undefined. I can get the function to work when I provide all the arguments but returns an empty array when I only pass two arguments. Here is the question:

Write a range function that takes two arguments, start and end, and returns an array containing all the numbers from start up to (and including) end.

Next, write a sum function that takes an array of numbers and returns the sum of these numbers. Run the previous program and see whether it does indeed return 55.

As a bonus assignment, modify your range function to take an optional third argument that indicates the “step” value used to build up the array. If no step is given, the array elements go up by increments of one, corresponding to the old behavior. The function call range(1, 10, 2) should return [1, 3, 5, 7, 9]. Make sure it also works with negative step values so that range(5, 2, -1) produces [5, 4, 3, 2].

And here is my code:

function range(start, end, increment){
var array = [];
var current = start;
var counter;
if (increment == undefined){
    counter = 1;
}

else {
    counter = increment;
}

if (increment > 0){
    while(current <= end){
        array.push(current);
        current += counter;
    }
}
  
else if (increment < 0){
    while(current >= end){
        array.push(current);
        current += counter;
        
    }
}

return array;
}

can someone explain why its breaking? I know some c# and I used to being able to jump into the debugger in visual studio when something goes wrong unlike javascript.

I am trying to make a function in javascript that returns an array from range(start,end) and im supposed to make an optional argument that defaults to one when it is undefined. I can get the function to work when I provide all the arguments but returns an empty array when I only pass two arguments. Here is the question:

Write a range function that takes two arguments, start and end, and returns an array containing all the numbers from start up to (and including) end.

Next, write a sum function that takes an array of numbers and returns the sum of these numbers. Run the previous program and see whether it does indeed return 55.

As a bonus assignment, modify your range function to take an optional third argument that indicates the “step” value used to build up the array. If no step is given, the array elements go up by increments of one, corresponding to the old behavior. The function call range(1, 10, 2) should return [1, 3, 5, 7, 9]. Make sure it also works with negative step values so that range(5, 2, -1) produces [5, 4, 3, 2].

And here is my code:

function range(start, end, increment){
var array = [];
var current = start;
var counter;
if (increment == undefined){
    counter = 1;
}

else {
    counter = increment;
}

if (increment > 0){
    while(current <= end){
        array.push(current);
        current += counter;
    }
}
  
else if (increment < 0){
    while(current >= end){
        array.push(current);
        current += counter;
        
    }
}

return array;
}

can someone explain why its breaking? I know some c# and I used to being able to jump into the debugger in visual studio when something goes wrong unlike javascript.

Share Improve this question edited Jan 25, 2021 at 0:23 peterh 1 asked Jun 1, 2016 at 12:30 user6127082user6127082 6
  • 1 JS has plenty of debugger as well. The one in Chrome is probably the best. Pop it open you'll be able to step through the code. – Evan Trimboli Commented Jun 1, 2016 at 12:31
  • The common JS idiom for if undefined, be this instead is: var counter = increment || 1; – castletheperson Commented Jun 1, 2016 at 12:35
  • @4castle could you explain further? not really sure how that works. would it be better to use the ? operator? – user6127082 Commented Jun 1, 2016 at 12:37
  • @Nate See this question, it explains it nicely. If the value on the left is falsey (aka undefined, null, 0, "", false or NaN) then it will assign the value on the right. – castletheperson Commented Jun 1, 2016 at 12:38
  • Related to stackoverflow.com/questions/3895478/… – aloisdg Commented Dec 3, 2022 at 15:44
 |  Show 1 more comment

9 Answers 9

Reset to default 6

A very simple unidirectional (ascending), inclusive range – goes from x to y incrementing by 1 each time.

// range :: (Int, Int) -> [Int]
const range = (x,y) =>
  x > y ? [] : [x, ...range(x + 1, y)];

console.log(range(1,4)); // [1,2,3,4]
console.log(range(3,3)); // [3]
console.log(range(6,3)); // []

A slight adaptation that supports bidirectional (ascending or descending) range – still increments or decrements by 1

// range :: (Int, Int) -> [Int]
const range = (x,y) => {
  if (x > y)
    return range(y,x).reverse();
  else
    return x === y ? [y] : [x, ...range(x + 1, y)];
}

console.log(range(1,4)); // [1,2,3,4]
console.log(range(3,3)); // [3]
console.log(range(6,3)); // [6,5,4,3]

Another adaptation that uses higher-order functions for more control over the range – this effectively gives you the stepping/incrementing behaviour some of you are looking for – tho this is more powerful because it lets you use a function, t, to choose the next value.

const gte = x => y => y >= x;
const lte = x => y => y <= x;
const add = x => y => y + x;
const sub = x => y => y - x;

// range :: (Int, (Int -> Bool), (Int -> Int)) -> [Int]
const range = (x, p, t) => {
  if (p(x))
    return [x, ...range(t(x), p, t)];
  else
    return [];
};

console.log(range(2, lte(8), add(2))); // [2,4,6,8]
console.log(range(9, gte(0), sub(3))); // [9,6,3,0]
console.log(range(9, gte(0), sub(5))); // [9, 4]

// very power. wow.
const double = x => x + x;
console.log(range(2, lte(50), double)); // [2,4,8,16,32]

This function has the same risks inherent with for and while – it's up to you to make sure you don't put it into an infinite loop.


functional overload

Warning: Esoteric, impractical functionals ahead. The following information is provided for your academic pleasure only.

The range function also happens to be one of my favourite demonstrations of the Y combinator. I'll show you two examples here.

naïve range

const U = f => f (f);
const Y = U (h => f => f (x => h (h) (f) (x)));

const range = Y (f => acc => x => y =>
  x > y ? acc : f ([...acc, x]) (x + 1) (y)
) ([]);

console.log(range (3) (6)); // [3,4,5,6]
console.log(range (6) (6)); // [6]
console.log(range (9) (6)); // []

and the higher-order range

const U = f => f (f);
const Y = U (h => f => f (x => h (h) (f) (x)));

const lt = x => y => y < x;
const gt = x => y => y > x;
const add1 = x => x + 1;
const sub1 = x => x - 1;

const range = Y (f => acc => x => p => t =>
  p(x) ? f ([...acc, x]) (t(x)) (p) (t) : acc 
) ([]);

console.log(range (3) (lt(6)) (add1)); // [3,4,5]
console.log(range (6) (lt(6)) (add1)); // []
console.log(range (9) (gt(6)) (sub1)); // [9,8,7]

What a thing of beauty that is.

You could simplify the code a bit and use the increment variable for incrementing. But before, I suggest to test if the value is falsy (0, null, undefined, etc) and assign then 1 to it.

Not implemented: check if start and end is appropriate.

function range(start, end, increment) {
    var array = [];
    var current = start;

    increment = increment || 1;
    if (increment > 0) {
        while (current <= end) {
            array.push(current);
            current += increment;
        }
    } else {
        while (current >= end) {
            array.push(current);
            current += increment;
        }
    }
    return array;
}

console.log(range(1, 3, 0));    
console.log(range(2, 5));
console.log(range(1, 9, 1));
console.log(range(5, 2, -1));    

First you check if increment is undefined and set counter accordingly, but later you check if (increment > 0){ again. While it is undefined none of your cases matches, so nothing happens.

Change your checks to this:

if (counter > 0){
  // ...
}
else if (counter < 0){
  // ...
}

Very compact range function that handles float and negative numbers:

const range = (lower,upper,step)=>{
  return Array.from(new Array(Math.floor(upper/step-lower/step)+1),(_,i)=>lower/step+i).map(x=>x*step)
}

For example you can use it like:

range(10,30,3) // [10, 13, 16, 19, 22, 25, 28]
range(0,0.5,0.01) // [0, 0.01, 0.02, ... , 0.48, 0.49, 0.5]
range(1,10,2) // [1, 3, 5, 7, 9]
range(-5,10,0.5) // [-5, -4.5, -4, ... , 1, 1.5, 2]
range(5,2,-0.5) // [5, 4.5, 4, 3.5, 3, 2.5, 2]

Here a more understandable version:

const range = (lower, upper, step) => {
  end = upper / step // Upper bound
  start = lower / step // Lower bound
  n = Math.floor(end - start) + 1 // Size that includes upper bound as well
  zeros_arr = Array(n).fill(0) // Init array with n zeros
  unscaled_arr = zeros_arr.map((_, i) => (start + i)) // Setting each zero to the upper bound + the index
  range_arr = unscaled_arr.map(x => (x * step)) // Scaling every numbers with the step
  return range_arr
}

I realize this is an extremely old question and you probably don't need it anymore, but just in case someone reads this, my favorite way to do this is using a generator:

function* rangeGenerator(start, end = null, step = 1) {
    if (end == null) {
        end = start
        start = 0
    }

    if (Math.sign(end - start) !== Math.sign(step)) {
        step *= -1
    }

    while (Math.sign(step) === 1 ? start < end : start > end) {
        yield start
        start += step
    }
}

const range = (start, end = null, step = 1) => [...rangeGenerator(start, end, step)]

This way, the range function will generate an array that goes from start (inclusive) to end (exclsive). step should always be provided as a positive number because the sign is automatically handled by the generator according to whiche of start and end is bigger. You can pass it a negative step, but it's unnecessary.

This gives you the ability to use a for of loop over the range

for (let i = 0; i < 100; i++) {}

// Is the same as
for (const i of range(100)) {}

The given answers are great. I just wanted to give you an idea of how a more functional approach could solve the task:

// auxiliary functions:
const append = (x, xs) => xs.concat([x]);
const prepend = (x, xs) => [x].concat(xs);

// main function
const range = (x, y, step, acc = [], op = append) =>
 step && step < 0
  ? range(y, x, -step, acc, prepend)
  : step && x <= y
   ? range(x + step, y, step, op(x, acc), op) // tail call
   : acc;

console.log(range(1,5,1)); // [1,2,3,4,5]
console.log(range(1,5,2)); // [1,3,5]
console.log(range(1,5,6)); // [1]
console.log(range(5,1,1)); // []
console.log(range(1,5,0)); // []
console.log(range(5,1,-1)); // [5,4,3,2,1]
console.log(range(5,1,-2)); // [5,3,1]
console.log(range(5,1,-6)); // [1]
console.log(range(1,5,-1)); // []

Algorithm:

  • acc = [] and op = append default parameter values (are taken if omitted during the function invocation)
  • step && step < 0 short circuits if step is zero, otherwise checks if step is negative
  • range(y, x, -step, acc, prepend) is called when step is negative and converts range's parameterization so that step can be positive (note that -step is equivalent with -(-1), which is evaluated to 1)
  • range(x + step, y, step, op(x, acc), op) recursive case that means, the function calls itself (notice that op can be either append or prepend depending on the initial sign of step, that x is increased by step and appended/prepended to acc)
  • acc base case that stops the recursion and returns the accumulated array

I solved this problem as part of the eloquent javascript course. Based on the problem statement I chose default parameters for the increments and used a while loop to include the second argument.


function range(start, stop, increment=1)
{
  let range_arr = [];
  if(start < stop)
  {
    while( start <= stop)
    {
      range_arr.push(start);
      start += increment;
    }
  }
  else{
    while( start >= stop)
    {
      range_arr.push(start);
      start += increment;
    }
  }
  return range_arr;
}

I decided to use the for loop to create the increments as follows.

function range(start,end) {
  let array = [];
  
  for (let counter = 0; counter < end; counter++) {
    array.push(start);
    start += 1;
  }
  return array;
  }
  console.log(range(1,10)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

I've using the snippet for range, with help of iterative callback theory.

That repeat the same function function with respected range attribute i.e 10-100. also 10-100 with 2 or 5 different.

function range(n, m, callback, k){
 if(!k) k=1;
 while(true){
  if(n<=m){
   callback(n);
   n+=k;
   if(n>=m) break;
  }else{
   callback(n);
   n-=k
   if(n<=m) break;
  }
 }
}

you can execute the snippet by

range(10, 100,function(n){
 // do here
},10)

you can extends the snippets by

function range_arr(n, m,callback,k) {
 let a = []
 range(n,m,function(n){
 a.push(callback(n))
 },k)
 return a;
}

you can use this snippet by

let arr=range_arr(0,10,function(n){
  return n=n*n;
 },2);

(5)[0, 4, 16, 36, 64]

发布评论

评论列表(0)

  1. 暂无评论