What would be the tersest way to create this array:
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
For example, a for
loop:
var x = []; for (var i=1;i<=20;i++) { x.push(i); }
Or a while
loop:
var x = [], i = 1, endInt = 20; while (i <= endInt) { x.push(i); i++; }
Would there be other examples that would be terser — in other words — less code? I’m thinking of things like in Ruby where the equivalent code I believe would be as simple as 1..20
. I’m not aware of syntax like that in JavaScript but I’m wondering if there are shorter ways to do that same thing.
UPDATE: I wasn’t thinking of removing semicolons or var
for answers in the question, but I have to admit the question implies that. I am more curious about algorithms than shaving bytes. Sorry if I was unclear! Also, making it into a function is simple enough, just slap function range(start, end) { /* guts here */ }
around it and you’re there. The question is are there novel approaches to the “guts.”
Advertisement
Answer
Favorite method
Update Sep13,2015:
Just came up with this new method which works with browsers which support the ES6 standard:
> Array(5).fill().map((x,i)=>i) [0, 1, 2, 3, 4]
Note the above does a tiny bit of extra work (fills with undefined
) but is relatively minor vis-a-vis the speedup you can achieve by using a for loop, and if you forget the .fill
you may be confused why your array is mysteriously [empty x 5]
. You can encapsulate the above as a custom function, or alternatively use a somewhat more intended method:
> Array.from(Array(5),(x,i)=>i) [0, 1, 2, 3, 4]
You can of course directly go from that into whatever you want to do, like python’s list comprehensions e.g. [i**2 for i in range(5)]
:
> Array.from(Array(5), (_,i)=> i**2) [0, 1, 4, 9, 16]
… or if you want to get more complicated…:
> Array.from(Array(5), (_,i)=> { const R = /*some computation*/; return /*etc*/; });
[edit May,2021]: theoretically tersest way of defining such a function nowadays is f=i=>i?[...f(i-1),i]:[]
, where you replace f with range1
or whatever the name is, but which would be very slow (quadratic complexity) due to intermediate structures so should never be used. f=i=>i?f(i-1)&&x.push(i)&&x:x=[]
is linear complexity but relies on abuse of notation and is unreadable and pollutes global variables as well. But, since defining arrow functions (which don’t bind but rather inherit this
) is pretty terse nowadays, you could just wrap the above solution:
const range1 = n=> Array.from(Array(n), (_,i)=> i+i); // range1(5)==[1, 2, 3, 4, 5]
Circumstantially, the tersest way to do a range(N)
, if you already have a list lying around of exactly that length N, is just to map
it: e.g. rather than do Array.from(Array(myArr.length), (_,i)=> i**2)
, you would just do myArr.map((_,i)=> i**2)
. (This has no side-effect unless you want it to.)
everything below is historical:
After thinking about it a bit, this is the shortest implementation of the standard range(N)
function in JavaScript I could come up with:
function range1(i){return i?range1(i-1).concat(i):[]}
Note: Do not use this in production; it’s O(N^2)
Contrast with current top-voted answer:
function range1(i){var x=[];var i=1;while(x.push(i++)<i){};return x}
Example:
> range1(5) [1, 2, 3, 4, 5]
This is like the poster child for recursion, though I was expecting it to be longer until I thought of ternary-if-statement, which brings it down to 42 necessary characters.
Note that the “standard” range
function returning [start,end) can be written by doing .concat(i-1)
.
Update: Ooh, I discovered an incredibly short version with ugly imperative syntax by abusing for loops, reverse-ordering, the fact that assignments return a value: for(y=[],i=20;y[--i]=i;){}
consisting of only 25 characters (though you will want var y
which you can insert into a for loop, and +1 if you don’t want 0…19). While it is not shorter if you need to define a function, it is shorter than i?r(i-1).concat(i):[]
if you do not need to make a function.
Added some performance profiling testcases: it seems that everything besides a standard in-order for-loop is 10x slower, at least on V8. https://jsperf.com/array-range-in-javascript (Of course, none of this matters if you’re programming in a functional style anyway and would hit every element with a function call anyway.)