1

I'm developing a solution on which I need to loop through two separate continuous number ranges. Lets say for example 1 to 5 and 10 to 15.

I'm using the following code:

var X = [];

for (i = 1; i < 6; i++) {
  X.push(i);
}
for (i = 10; i < 16; i++) {
  X.push(i);
}

for (var x in X) {      
  console.log(parseInt(X[x]));
}

This code does the job, but have a lot of overhead and unnecessary operations:

  • Spending time filling array with desired ranges
  • Accessing element by index for getting the true value (X[x])
  • Converting the value back to integer using parseInt (as the type X[x] is string)

Is there any simpler/more efficient way to perform this kind of operation? Something like this:

for(x = 1 to 5, then x = 10 to 15) {
  // do something with x
}

Constraints:

  • Using two separate loops with same code inside is not useful as this loop is repeated on several locations on the code
  • Packaging the contents of the loops inside functions is not desirable
  • Checking for x boundaries and updating its value inside loop is also not desirable (I mean, checking if x == 5 and then changing it to 10)

I've searched through SO but couldn't find any solution for this.

Thanks in advance!

GCSDC
  • 3,138
  • 3
  • 28
  • 48
  • you are not saying what the desired out it? – blurfus May 15 '17 at 23:59
  • How about a function that returns a static array - function do(){ return [1,2,3,4,5,10,11,12,13,14,15]; } – user2182349 May 16 '17 at 00:02
  • 1
    The `parseInt` in your code isn't necessary. `X[x]` is already an integer. It's `x` which is a string. Also, [don't use a `for...in` loop to iterate over an array](http://stackoverflow.com/q/500504/5743988). – 4castle May 16 '17 at 01:11

3 Answers3

5

You can use for..of loop, for loop, spread element

let res = [];

for (let [from, to] of [[1, 6], [10, 16]]) 
  for (let x = from; x < to; x++) console.log(x); res.push(x);

console.log(res);

If requirement is to only log digits at console, or "// do something with x" without storing result of "something" in an array, we can reduce javascript to

for (let [from, to] of [[1, 6], [10, 16]])
  for (let x = from; x < to; x++) console.log(x); // do stuff with `x`
guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    is it just me or is javascript looking less and less like the javascript of old :p I love this sort of code :p – Jaromanda X May 16 '17 at 00:16
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144295/discussion-between-4castle-and-guest271314). – 4castle May 16 '17 at 00:36
3

In ES6 you could create some generator functions which abstract away the looping details, and use a for...of loop. This way you will have the readable syntax you're looking for, while not creating any large arrays.

function* ranges(...rangeDescriptors) {
  for (const [min, max, step = 1] of rangeDescriptors)
    for (let i = min; i < max; i += step)
      yield i;
}

for (const x of ranges([1, 6], [10, 16])) {
  console.log(x);
}
4castle
  • 32,613
  • 11
  • 69
  • 106
2

This isn't necessarily more efficient, but it does keep everything nice and tidy and prevents duplication of code.

Basically, write a function that accepts an array of ranges and a callback to be executed on each iteration of the loop through the specified ranges.

The range and current index are passed to the callback, should they be needed.

function loop(ranges, callback) {
  ranges.forEach(function (range) {
    for (var i = range[0]; i <= range[1]; i++) callback(range, i);
  });
}

var ranges = [
  [1, 5],
  [10, 15],
];

var callback = function (range, i) {
  console.log(i);
}

loop(ranges, callback);
fubar
  • 16,918
  • 4
  • 37
  • 43
  • This seems to better match what the OP was asking for (than the other answers) as it doesn't create an intermediate array and then iterate it, but rather just iterates the passed in ranges. This is what I would have written if I needed this kind of functionality. – jfriend00 May 16 '17 at 00:21
  • Thanks everyone for helping. Upvoted answers from 4castle, guest271314 and fubar as all of them would solve the problem as expected. This was the chosen answer as it was the "cleaner" approach considering what I was looking for, and also had the best performance, as tested [here](https://jsperf.com/loop-range-original/). – GCSDC May 17 '17 at 19:34
  • @GCSDC The JSPerf you linked to showed no meaningful difference in speed. They're all within 0.01 op/sec of one another. – 4castle May 18 '17 at 08:26