24

What is the fastest algorithm for getting from something like this:

var array = [ [1,'a'], [2,'b'], [3,'c'] ];

to something like this:

Object { 1: "a", 2: "b", 3: "c" }

so far this is what i've come up with:

function objectify(array) {
    var object = {};
    array.forEach(function(element) {
        object[element[0]] = element[1];
    });
    return object;
}

which works fine, but it seems kind of clumsy. Is there a better way? Would something like reduce() work and would that be any faster?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Fred Guest
  • 313
  • 1
  • 2
  • 7

5 Answers5

33

You can use Object.fromEntries to convert an Array to an Object:

var array = [
  [1, 'a'],
  [2, 'b'],
  [3, 'c']
];
var object = Object.fromEntries(array);
console.log(object);
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
  • 2
    This is the "correct" answer, and much nicer than the `reduce` approach. Only use `reduce` if you need to target very old browsers (eg IE) – tel Jun 02 '20 at 09:29
  • 1
    What an elegant way of getting things done. This code snippet does the job without any further complications. – Arun Ramachandran Jan 07 '21 at 14:36
22

You could indeed use Array.prototype.reduce:

function objectify(array) {
    return array.reduce(function(p, c) {
         p[c[0]] = c[1];
         return p;
    }, {});
}

where p is the result of the previous iteration, initially {}, and c is the current element of the array.

It's unlikely to be any faster than array.forEach, but it is IMHO cleaner. I don't believe there's any simpler implementation than this.

NB: a function to do exactly this already exists in the Underscore library: _.object(array)

Alnitak
  • 334,560
  • 70
  • 407
  • 495
9

Terse version using modern syntax:

let objectify = a => a.reduce( (o,[k,v]) => (o[k]=v,o), {} );

I use this technique as part of a terse query string parser:

// Converts "?foo=bar&j=1&go" into { foo:'bar', j:'1', go:true }
function parseQueryString(qs) {
    var q = decodeURIComponent;
    return qs.replace(/^\?/,'').split('&').map(s => s.split('='))
             .reduce((o,[k,v]) => (o[q(k)] = v?q(v):true, o), {});
}
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 2
    This works perfectly for my use case. I consider myself pretty proficient in ESXXXX but I can't quite figure out how that lambda is working. Specifically the `(o[k]=v,o)` part. Any insights? Also, thanks for sharing this gem. :-) – KyleFarris Apr 17 '18 at 22:13
  • 2
    @KyleFarris it's using the comma operator to perform the assignment into the map, and then return `o` itself. – Alnitak May 02 '18 at 10:55
7

Lodash has a _.fromPairs method that does exactly that.

From the documentation:

_.fromPairs([['a', 1], ['b', 2]]);
// => { 'a': 1, 'b': 2 }  
VLAZ
  • 26,331
  • 9
  • 49
  • 67
Uri Klar
  • 3,800
  • 3
  • 37
  • 75
2

You can wrap the entire thing within Array.prototype.reduce, like this

function objectify(array) {
    return array.reduce(function(result, currentArray) {
        result[currentArray[0]] = currentArray[1];
        return result;
    }, {});
}

console.log(objectify([ [1, 'a'], [2, 'b'], [3, 'c'] ]));
# { '1': 'a', '2': 'b', '3': 'c' }

We are just accumulating the key-value pairs in the result object and finally the result of reduce will be the result object and we are returning it as the actual result.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497