7

Is there a simple way in javascript to take a flat array and convert into an object with the even-indexed members of the array as properties and odd-indexed members as corresponding values (analgous to ruby's Hash[*array])?

For example, if I have this:

[ 'a', 'b', 'c', 'd', 'e', 'f' ]

Then I want this:

{ 'a': 'b', 'c': 'd', 'e': 'f' }

The best I've come up with so far seems more verbose than it has to be:

var arr = [ 'a', 'b', 'c', 'd', 'e', 'f' ];
var obj = {};
for (var i = 0, len = arr.length; i < len; i += 2) {
    obj[arr[i]] = arr[i + 1];
}
// obj => { 'a': 'b', 'c': 'd', 'e': 'f' }

Is there a better, less verbose, or more elegant way to do this? (Or I have just been programming in ruby too much lately?)

I'm looking for an answer in vanilla javascript, but would also be interested if there is a better way to do this if using undercore.js or jQuery. Performance is not really a concern.

Ben Lee
  • 52,489
  • 13
  • 125
  • 145

4 Answers4

9

Pretty sure this will work and is shorter:

var arr = [ 'a', 'b', 'c', 'd', 'e', 'f' ];
var obj = {};
while (arr.length) {
    obj[arr.shift()] = arr.shift();
}

See shift().

calebds
  • 25,670
  • 9
  • 46
  • 74
  • No guarantees about speed, however. – calebds Jan 05 '12 at 23:07
  • 3
    I like this! But you should probably note as a caveat that this consumes the original array, so it only works if you don't care about the original. – Ben Lee Jan 05 '12 at 23:08
  • Character wise it is shorter but is it truly the most optimal solution? A question for the ages... – ChaosPandion Jan 05 '12 at 23:09
  • @ChaosPandion, it depends on how you define optimal. The "optimizatoin" I was looking for a concise and readable version, and this fits the bill for me. – Ben Lee Jan 05 '12 at 23:11
  • 2
    You could also do this: `var obj = {}, k, v; while(k = arr.shift(), v = arr.shift()) { obj[k] = v;}`, which would even work with an odd number of elements (ignoring the last one). – Felix Kling Jan 05 '12 at 23:33
5
var arr = [ 'a', 'b', 'c', 'd', 'e', 'f' ];
var obj = arr.reduce( function( ret, value, i, values ) {

    if( i % 2 === 0 ) ret[ value ] = values[ i + 1 ];
    return ret;

}, { } );
goofballLogic
  • 37,883
  • 8
  • 44
  • 62
0

If you need it multiple times you can also add a method to the Array.prototype:

Array.prototype.to_object = function () {
  var obj = {};
  for(var i = 0; i < this.length; i += 2) {
    obj[this[i]] = this[i + 1]; 
  }
  return obj
};

var a = [ 'a', 'b', 'c', 'd', 'e', 'f' ];

a.to_object();    // => { 'a': 'b', 'c': 'd', 'e': 'f' }
TNT
  • 3,392
  • 1
  • 24
  • 27
0

You could first chunk your array into groups of two:

[['a', 'b'], ['c', 'd'], ['e', 'f']]

so that is is in a valid format to be used by Object.fromEntries(), which will build your object for you:

const chunk = (arr, size) => arr.length ? [arr.slice(0, size), ...chunk(arr.slice(size), size)] : [];
const arr = ['a', 'b', 'c', 'd', 'e', 'f'];
const res = Object.fromEntries(chunk(arr, 2));
console.log(res); // {a: "b", c: "d", e: "f"}

With underscore.js and lodash, you don't need to implement the chunk() method yourself, and can instead use _.chunk(), a method built into both libraries. The full lodash equivalent of the above would be:

// lodash
> _.fromPairs(_.chunk(arr, 2)); 
> {a: "b", c: "d", e: "f"}

Using _.fromPairs provides better browser support, so if using lodash, it is preferred over Object.fromEntries()

Similarly, we can use _.object() if you're using underscore.js to build the object:

// underscore.js
> _.object(_.chunk(arr, 2));
> {a: "b", c: "d", e: "f"}
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64