Trying my hand at (code) golf

I’ve never attempted code golf before but encountered the following tweet that looked achievable.

JS Golf #4: play(“hello=goodbye&answer=42&x=y”) === {hello:”goodbye”,answer:”42”,x:”y”} (parse url encoded parameter strings into objects)

JS Golf #4

I thought I’d describe the journey to my shortest solution (lower score is better) which ended up touching on a few of JavaScript’s newer language features.

An unoptimised solution

Here’s my starting “normal” code that does the job.

function play(querystring) {
return querystring.split('&').reduce(function(object, param) {
const parts = param.split('=')
object[parts[0]] = parts[1]
return object
}, {})
}

Score: 104

Apply some manual minification.

function play(q){return q.split('&').reduce(function(o,p){let k=p.split('=');o[k[0]]=k[1];return o},{})}

Score: 81

Arrow functions are shorter, don’t require parentheses when there’s a single argument, and implicitly return when used without braces.

play=q=>q.split('&').reduce((o,p)=>{let a=p.split('=');o[a[0]]=a[1];return o},{})

Score: 79

Use destructuring assignment.

play=q=>q.split('&').reduce((o,p)=>{let [k,v]=p.split('=');o[k]=v;return o},{})

Score: 75

Don’t worry about setting global variables 😱

play=q=>q.split('&').reduce((o,p)=>{[k,v]=p.split('=');o[k]=v;return o},{})

Score: 71

Template literals also call a function so there’s no need for parentheses.

play=q=>q.split`&`.reduce((o,p)=>{[k,v]=p.split`=`;o[k]=v;return o},{})

Score: 65

Arrow function implicit returns again. I couldn’t use a semicolon to turn the function body into a single line but a comma works.

play=q=>q.split`&`.reduce((o,p)=>([k,v]=p.split`=`,o[k]=v)&&o,{})

Score: 64

Using another comma instead of && is possible as the comma operator returns the last expression.

play=q=>q.split`&`.reduce((o,p)=>([k,v]=p.split`=`,o[k]=v,o),{})

Score: 60

I started looking at whether I could use something other than reduce as its multiple arguments mean parenthesis can’t be removed. In the good old days before ES5 introduced reduce and friends I would have created the data object manually by looping through the array adding properties to it like so:

function play(querystring) {
var object = {}
var params = querystring.split('&')

for (var i = 0; i < params.length; i++) {
var keyvalue = params[i].split('=')
object[keyvalue[0]] = keyvalue[1]
}

return object
}

It turns out that this technique actually shortens the code by a further 4 characters, particularly as nowadays we don’t need to use a verbose for loop. So play now loops over the querystring’s parameters setting key/value pairs on an accumulator object which it then returns — using map instead of forEach for its shorter name.

o={},play=q=>q.split`&`.map(p=>([k,v]=p.split`=`,o[k]=v))&&o

The winner? Yes!

This solution currently shares the top score of 60 characters — someone got there first with an essentially identical version.

It’s been an interesting exercise and taking a deeper look into some of JavaScript’s features has been useful — despite being focussed on hacky ways to shorten code. Re-adding whitespace and proper variable names gives us the shape of the code which looks remarkably Lisp-ish and very un-JavaScript.

object = {},
play = querystring =>
querystring.split `&`
.map(
param => (
[key, value] = param.split `=`,
object[key] = value
)
) && object

Bonus round: a different approach. Score: 63

I wondered if something could be done about the two uses of split so tried a different approach, this time creating an array of key/values with a single split. Combined with the lessons learned so far it’s a good effort but falls just short at 63 characters.

o={},play=q=>q.split(/[&=]/).map((p,i,a)=>i%2?o[a[i-1]]=p:p)&&o

Update: Thanks to @Benjie for removing another valuable character:

o={},play=q=>q.split(/&|=/).map((p,i,a)=>i%2?o[a[i-1]]=p:p)&&o

For good measure here it is deminified:

object = {},
play = querystring =>
querystring.split(/&|=/)
.map(
(param, index, array) =>
index % 2
? object[array[index - 1]] = param
: 1
) && object

Originally published at www.benpickles.com