Generating the alphabet in JavaScript

22

5

I'm pretty sure there's not a better way to do this but figured it couldn't hurt to ask.

I'm tired of typing out a='abcdefghijklmnopqrstuvwxyz'.

Cool languages have Range('a'..'z') or similar

What can we come up with with JS that's as short as possible??

for(i=97,a='';i<123;){a+=String.fromCharCode(i++)}

is longer than just the alphabet - but guarantees I don't screw up somewhere.

I'm hoping there's a nasty bit-shifty way to produce a-z in less than 50 characters.

I messed around with i=97;Array(26).map(x=>String.fromChar....i++

but it was always way longer by the time I joined then split the array(26) to be useable


Edit: I've gotten it down to

[...Array(26)].reduce(a=>a+String.fromCharCode(i++),'',i=97)

60 bytes

Charlie Wynn

Posted 2016-02-09T21:08:14.367

Reputation: 696

11

@muddyfish, LuisMendo: This is on-topic per meta.

– Doorknob – 2016-02-09T21:11:34.547

1[...Array(26)].map((q,w)=>String.fromCharCode(w+97)) is 52 bytes and add another 7 for the .join\`` – andlrc – 2016-02-09T21:13:42.623

@dev-null a='';i=97;[...Array(26)].map(b=>a+=String.fromCharCode(i++)) is 60 but takes care of the join how are you doing join in 7 without getting commas in the result? – Charlie Wynn – 2016-02-09T21:19:46.170

1@CharlieWynn [...Array(26)].map((q,w)=>String.fromCharCode(w+97)).join\`` – andlrc – 2016-02-09T21:23:49.887

@dev-null join`` is new to me! – Charlie Wynn – 2016-02-09T21:25:20.203

Answers

12

Alternative to String.fromCharCode

... if you are happy with a lowercase only alphabet.

for(i=9,a='';++i<36;)a+=i.toString(36) // 38, cannot be used in an expression
[...Array(26)].map(_=>(++i).toString(36),i=9).join`` // 52 directly returnig the string desired
[...Array(26)].map(_=>a+=(++i).toString(36),a='',i=9) // 53 assign to a variable
(i=9,[for(_ of Array(26))(++i).toString(36)].join``) // 52 ES7 direct return
i=9,a='',[for(_ of Array(26))a+=(++i).toString(36)] // 51 ES7 assign to a variable

edc65

Posted 2016-02-09T21:08:14.367

Reputation: 31 086

1Oh dang, that is clever. So it's starting with 10, converting to base 36 and printing it? so a-z! – Charlie Wynn – 2016-02-10T14:46:34.097

Are those a='' and i=9 arguments of map function call? Checked Array.prototype.map() on mdn and it doesn't look like map support such arguments.. – Jay Somedon – 2019-01-22T14:10:30.327

@JaySomedon those are argument for map function call, in a way, Javascript functions tipically don't care and discard parameters they do not expect. So I initialize a variable I need, while adding a parameter that is of no use for the called function – edc65 – 2019-01-22T15:35:03.237

@JaySomedon see also this answer and related comments https://codegolf.stackexchange.com/a/2684/21348

– edc65 – 2019-01-22T15:40:10.203

@edc65 aha I see! That's neat! So here, when javascript evaluates arguments like i=9 in map(), it actually creates a global variable i then assigns 9 to that? – Jay Somedon – 2019-01-23T07:42:31.303

@JaySomedon correct – edc65 – 2019-01-23T10:46:14.113

@edc65 One more thing, are these same: var a = [...Array(26)], var b = Array(26), var c = new Array(26)? In console, a prints [undefined, undefined..] and b and c print [empty slots...] but all a[0]``b[0]``c[0] evaluate to undefined. But only calling map on [...Array(26)] gives me alphabets, calling on the other two give me nothing, wonder why. Also on mdn, I can't find any example about Array(n), so I wonder how Array(n) and new Array(n) are related with each other? – Jay Somedon – 2019-01-23T11:05:37.967

12

Note: All of these techniques assign the alphabet string to variable a.


I am 99% certain that the shortest way to achieve this in JavaScript is indeed:

a="abcdefghijklmnopqrstuvwxyz" // 30 bytes

But there are several other interesting methods. You can use string compression:

a=btoa`i·?yø!?9%?z)ª»-ºü1`+'yz' // 31 bytes; each ? represents an unprintable

You can get the compressed string from atob`abcdefghijklmnopqrstuvwx`. The 'yz' must be added manually because if you compress the whole string, while the result is only 27 bytes, it will turn out as abcdefghijklmnopqrstuvwxyw==.

I believe the shortest way to do it programmatically is also the method you suggested:

for(i=97,a='';i<123;)a+=String.fromCharCode(i++) // 48 bytes

You can do it with ES6 features (template strings ``, spread operator ...) if you want:

a=[...Array(26)].map(_=>String.fromCharCode(i++),i=97).join`` // 61 bytes
a=[...Array(26)].map((_,i)=>String.fromCharCode(i+97)).join`` // also 61 bytes
a=[...Array(i=26)].map(_=>String.fromCharCode(++i+70)).join`` // again, 61 bytes

You can do one better with a variable instead of .join``:

[...Array(26)].map(_=>a+=String.fromCharCode(i++),i=97,a='') // all 60 bytes
[...Array(26)].map((_,i)=>a+=String.fromCharCode(i+97),a='')
[...Array(i=26)].map(_=>a+=String.fromCharCode(++i+70),a='')

Or ES7 with array comprehensions, which is another byte shorter:

a=[for(_ of Array(i=26))String.fromCharCode(++i+70)].join`` // 59 bytes

Creating the variable beforehand saves yet another byte:

a='',[for(_ of Array(i=26))a+=String.fromCharCode(++i+70)] // 58 bytes

Also, String.fromCharCode accepts multiple arguments and will automatically join them. So we can golf each ES6 version down to 57 bytes:

a=String.fromCharCode(...[...Array(26)].map(_=>i++,i=97)) // all 57 bytes
a=String.fromCharCode(...[...Array(26)].map((_,i)=>i+97))
a=String.fromCharCode(...[...Array(i=26)].map(_=>++i+70))

And the ES7 one down to 55:

a=String.fromCharCode(...[for(_ of Array(i=26))++i+70]) // 55 bytes

If you'd like to learn more about golfing ranges, check out this set of tips. There's also one about ES7's array comprehensions.

EDIT: As edc65 has pointed out, most of these become shorter using i.toString(36) instead of String.fromCharCode(i):

for(i=9,a='';++i<36;)a+=i.toString(36) // 38 bytes
a=[...Array(26)].map(_=>(++i).toString(36),i=9).join`` // 54 bytes
[...Array(26)].map(_=>a+=(++i).toString(36),i=9,a='') // 53 bytes
i=9,a=[for(_ of Array(26))(++i).toString(36)].join`` // 52 bytes
i=9,a='',[for(_ of Array(26))a+=(++i).toString(36)] // 51 bytes

I believe this one is the shortest possible that can be called as a function return value:

eval("for(i=9,a='';++i<36;)a+=i.toString(36)") // 46 bytes

It's three bytes shorter than manually returning it from a function:

x=>eval("for(i=9,a='';++i<36;)a+=i.toString(36)") // 49 bytes
x=>{for(i=9,a='';++i<36;)a+=i.toString(36);return a} // 52 bytes

Of course, x=>"abcdefghijklmnopqrstuvwxyz" still beats everything else.

ETHproductions

Posted 2016-02-09T21:08:14.367

Reputation: 47 880

I really like where this is going - just wish I could ES7 in chrome :( – Charlie Wynn – 2016-02-09T21:42:32.547

3@CharlieWynn Yes, it's a shame that not all browsers support all the latest features. But after all, Chrome wasn't built in a day... ;) – ETHproductions – 2016-02-09T21:53:39.333

Most of these solution can be shortened using .toString instead of String,.fromCharCode. See my answer – edc65 – 2016-02-09T22:42:10.477

1@CharlieWynn I think Chrome Beta now supports all of ES7 and all of ES6 except modules and tail call optimisation. – gcampbell – 2016-06-10T10:28:33.290

Here's a 42-byter that can be called as a function return value: (f=(i=9)=>++i<36?i.toString(36)+f(i):'')() – Rick Hitchcock – 2017-07-03T23:45:14.053

@ETHproductions for this code [...Array(26)].map(_=>String.fromCharCode(i++),i=97).join() how is i iterating? It's not even declared? Even if it were how is it that it's not set back to 97 each loop? I'm really confused. I looked at documentation but I must be missing something. – zfrisch – 2017-12-08T18:05:03.587

@zfrisch It's declared as the second argument to map (which doesn't affect anything): i=97. Then each time the function _=>String.fromCharCode(i++), it's incremented by 1. – ETHproductions – 2017-12-08T21:28:18.123

@ETHproductions cool! I would've expected, since the second parameter looks like it's a this context, that if it wasn't a valid this context that it would have just thrown an error. The more you know. – zfrisch – 2017-12-08T21:43:56.093

7

Here's another approach, a 51 byte ES6 expression:

String.fromCharCode(...Array(123).keys()).slice(97)

50 bytes in upper case of course.

Neil

Posted 2016-02-09T21:08:14.367

Reputation: 95 035

For upper case: String.fromCharCode(...Array(91).keys()).slice(65) – jpoppe – 2017-01-31T16:27:32.847

1

Using what may or may not be defined at global scope

39 bytes for object properties to array matching a-z

a=`${Object.keys(top)}`.match(/[a-z]/g)

48 bytes for an unsorted Set

a=new Set(`${Object.keys(top)}`.match(/[a-z]/g))

55 bytes for a sorted Set

a=new Set(`${Object.keys(top)}`.match(/[a-z]/g).sort())

67 bytes for a sorted string

a=[...new Set(`${Object.keys(top)}`.match(/[a-z]/g).sort())].join``

guest271314

Posted 2016-02-09T21:08:14.367

Reputation: 1

1

36 bytes, using a trick I just learned about (from this post: https://codegolf.stackexchange.com/a/176496/64538):

for(i=9;++i<36;)name+=i.toString(36)

window.name is an empty string by default.

Of course, this is even less practical than the 38-byte solution since it uses a longer variable name.

12Me21

Posted 2016-02-09T21:08:14.367

Reputation: 6 110