9

I have two numbers, min and max, and I want to create an array that contains all number between them (including min and max).

The most obvious approach is to use a for loop for this, and push the single values onto an array. Nevertheless, this seems to be a quite naive approach, i.e. it's imperative programming.

Now I was thinking of how to create such an array in a more functional style. Basically, something such as the reverse of a reduce function: Instead of reducing an array to a number, building up an array from two numbers.

How could I do this? What is a functional approach to solve this problem?

Basically, I'm thinking of something such as 10..20 in some other languages. What's the most elegant equivalent for this in JavaScript?

2
  • 2
    Are you asking for an elegant or for a functional way? Commented Mar 18, 2014 at 11:51
  • Both ;-). It should be functional (from a technical point of view), but well readable as well. Commented Mar 18, 2014 at 12:00

6 Answers 6

13

Inspired by this

var min = 3, max = 10;
var x = Array.apply(null, {length: max + 1}).map(Number.call, Number).slice(min);
console.log(x);
// [ 3, 4, 5, 6, 7, 8, 9, 10 ]

The optimum version

var min = 3, max = 10;
var x = Array.apply(null, {length: max + 1 - min}).map(function(_, idx) {
    return idx + min;
});
console.log(x);
// [ 3, 4, 5, 6, 7, 8, 9, 10 ]
Sign up to request clarification or add additional context in comments.

7 Comments

This works. It's only drawback IMHO is that you first create an array with all number from 1 to max (which is not so very nice if you need only ten numbers which start at 1 billion ;-)). But apart from that: Nice solution :-)
It seems overly complicated. A for loop does the job as well, minus the useless complexity.
You should use slice instead of splice
@Bergi Got it. Updated. :)
@GoloRoden Did you check the optimum version, that creates an array of required size only. So, it doesn't waste memory.
|
9

A one line way. Inspired by How to create an array containing 1...N.

Array.from({length: max-min+1}, (_, i) => i + min);

Initiate an array from a computed length based on max and min. Then map each index value by a function which is "index + min". The reference is here.

Example:

const min = 12;
const max = 20;
const arr = Array.from({length: max-min+1}, (_, i) => i + min);

Comments

4

You can think of a "functional" definition of range:

range(low, hi) = [], if low > hi
range(low, hi) = [low] (+) range(low+1,hi), otherwise,

which leads to the JS definition:

function range(low,hi){
  function rangeRec(low, hi, vals) {
     if(low > hi) return vals;
     vals.push(low);
     return rangeRec(low+1,hi,vals);
  }
  return rangeRec(low,hi,[]);
}

2 Comments

I think, you can remove one more line and do return rangeRec(low+1,hi, vals.concat(low));
@thefourtheye: Yes, that would be much more functional (and you should move rangeRec outside of range then), but creating a new array on each iteration slows it down dramatically (O(n²) runtime)
1

If you have harmony generators you can use this:

function* range(lorange,hirange){
  var n = lorange;
  while (n <= hirange){
    yield n++;
  }
}

rval= range(3,6);

Now you can :

  1. Use the for-of comprehension for iterators as substitute of array

    for (i of rval)
    console.log(i);
    
    3
    4
    5
    6
    
  2. Or you can use it to create an array like you want

    rarray = [];
    for (i of rval)
    rarray.push(i);
    

2 Comments

The idea is great :-)). Unfortunately, I need such an ranged array to explain what generators are about ;-).
@GoloRoden This is a good substitute for the 10..20 range interpolation. It is like the xrange in python 2.7 which returns elements only when needed.
1

Might be late to the party, but, based on this (es6)

const rangexy = (start, end) => Array.from({length: (end+1 - start)}, (v, k) => k + start);

1 Comment

And then, just after posting I realized @juminet posted a very similar one. Hehe
0

Here is good exmaples.

const range = (min, max) => [...Array(max - min + 1).keys()].map((i) => i + min);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.