Optimizing small constant ranges for map()
Context
Starting with ES6, it has become fairly common to use (and abuse) the map()
method instead of a for
loop to iterate over a range \$[0..N-1]\$, so that the entire answer can be written in functional style:
for(i = 0; i < 10; i++) {
do_something_with(i);
}
can be replaced by either:
[...Array(10).keys()].map(i => do_something_with(i))
or more commonly:
[...Array(10)].map((_, i) => do_something_with(i))
However, using Array(N)
is rarely optimal when \$N\$ is a small constant.
Optimizations for a range \$[0..N-1]\$, with counter
Below is a summary of shorter alternate methods when the counter \$i\$ is used within the callback:
N | Method | Example | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 6 | use a raw array of integers | [0,1,2,3].map(i=>F(i)) | 2N+10
N = 7 | use either a raw array of integers | [0,1,2,3,4,5,6].map(i=>F(i)) | 24
| or a string if your code can operate | [...'0123456'].map(i=>F(i)) | 23
| with characters rather than integers | |
8 ≤ N ≤ 9 | use scientific notation 1e[N-1] | [...1e7+''].map((_,i)=>F(i)) | 24
N = 10 | use scientific notation 1e9 | [...1e9+''].map((_,i)=>F(i)) | 24
| or the ES7 expression 2**29+'4' if | [...2**29+'4'].map(i=>F(i)) | 23
| the order doesn't matter and your | |
| code can operate with characters | (order: 5,3,6,8,7,0,9,1,2,4) |
| rather than integers | |
11 ≤ N ≤ 17 | use scientific notation 1e[N-1] | [...1e12+''].map((_,i)=>F(i)) | 25
N = 18 | use the fraction 1/3 | [...1/3+''].map((_,i)=>F(i)) | 24
N = 19 | use the fraction 1/6 | [...1/6+''].map((_,i)=>F(i)) | 24
20 ≤ N ≤ 21 | use scientific notation 1e[N-1] | [...1e20+''].map((_,i)=>F(i)) | 25
N = 22 | use scientific notation -1e20 | [...-1e20+''].map((_,i)=>F(i)) | 26
23 ≤ N ≤ 99 | use Array(N) | [...Array(23)].map((_,i)=>F(i)) | 27
NB: The length of the callback code F(i)
is not counted.
Optimization for the range \$[1..9]\$, with counter
If you'd like to iterate over the range \$[1..9]\$ and the order doesn't matter, you can use the following ES7 expression (provided that your code can operate with characters rather than integers):
[...17**6+'8'].map(i=>F(i)) // order: 2,4,1,3,7,5,6,9,8; length: 23
Optimizations without counter
The following methods can be used if you just need to iterate \$N\$ times, without using a counter:
N | Method | Example | Length
------------+--------------------------------------+---------------------------------+-------
N ≤ 5 | use a raw array of integers | [0,0,0,0].map(_=>F()) | 2N+10
6 ≤ N ≤ 10 | use scientific notation 1e[N-1] | [...1e7+''].map(_=>F()) | 20
11 ≤ N ≤ 17 | use scientific notation 1e[N-1] | [...1e12+''].map(_=>F()) | 21
N = 18 | use the fraction 1/3 | [...1/3+''].map(_=>F()) | 20
N = 19 | use the fraction 1/6 | [...1/6+''].map(_=>F()) | 20
20 ≤ N ≤ 21 | use scientific notation 1e[N-1] | [...1e20+''].map(_=>F()) | 21
N = 22 | use scientific notation -1e20 | [...-1e20+''].map(_=>F()) | 22
23 ≤ N ≤ 99 | use Array(N) | [...Array(23)].map(_=>F()) | 23
NB: The length of the callback code F()
is not counted.
3Now I have a downvote here. Obviously someone noted something terribly wrong in this tip, being too shy to leave a comment and explain what ... – edc65 – 2016-02-09T21:04:17.220
It looks alright. Maybe it was the lack of semicolons? ;) (btw, you can also use it as rest parameters, like splats in Ruby) – gcampbell – 2016-05-25T09:46:00.530
You could add that it also has a use case in function signatures :) – Felix Dombek – 2017-07-18T11:17:42.493
Misclick did not mean to downvote – Stan Strum – 2017-10-01T01:20:16.587
@StanStrum it happens. I'll make a small update to this post so you can eventually change your vote (or you already did?) – edc65 – 2017-10-01T09:31:55.310
@FelixDombek done – edc65 – 2017-10-01T09:35:37.000
Maybe the downvoter was mislead by the “TypeError: values is not iterable” thrown when trying to run Use case 1 in global space. I think in such cases it refers to
– manatwork – 2017-10-01T09:56:03.640Object.values()
, but works fine inside a closure. I would suggest to rename that variable in your example.@manatwork don't see what you mean, I tried use case 1 in console with Firefox, Chrome and Edge. It works perfectly – edc65 – 2017-10-01T10:16:11.117
Seems to be Firefox related https://i.stack.imgur.com/S4kPX.png In Chromium indeed works everywhere.
– manatwork – 2017-10-01T10:41:49.873Could you please try
var values ...
to see if that works? Thanks for your time @manatwork – edc65 – 2017-10-01T11:59:06.390Nope. This time is really weird: https://i.stack.imgur.com/o0AMa.png
– manatwork – 2017-10-01T12:58:09.437Let us continue this discussion in chat.
– edc65 – 2017-10-01T13:47:49.417@edc65 I did, yes – Stan Strum – 2017-10-01T15:30:52.947