58

I have:

var keys = [ "height", "width" ];
var values = [ "12px", "24px" ];

And I'd like to convert it into this object:

{ height: "12px", width: "24px" }

In Python, there's the simple idiom dict(zip(keys,values)). Is there something similar in jQuery or plain JavaScript, or do I have to do this the long way?

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
itsadok
  • 28,822
  • 30
  • 126
  • 171
  • The same question with underscore.js: [merge two arrays of keys and values to an object using underscore](/q/12199051/4642212). – Sebastian Simon Sep 07 '21 at 09:32

14 Answers14

44

The simplest ES6 one-liner solution using Array reduce:

const keys = ['height', 'width'];
const values = ['12px', '24px'];
const merged = keys.reduce((obj, key, index) => ({ ...obj, [key]: values[index] }), {});

console.log(merged);
Yiin
  • 659
  • 6
  • 9
31

Simple JS function would be:

function toObject(names, values) {
    var result = {};
    for (var i = 0; i < names.length; i++)
         result[names[i]] = values[i];
    return result;
}

Of course you could also actually implement functions like zip, etc as JS supports higher order types which make these functional-language-isms easy :D

olliej
  • 35,755
  • 9
  • 58
  • 55
26

use lodash.

_.zipObject

Example

_.zipObject(['a', 'b'], [1, 2]);
// ➜ { 'a': 1, 'b': 2 }
anguskwan
  • 467
  • 5
  • 6
  • This should be the accepted answer. Rolling it yourself (like in all other answers) is a waste of time. The original name of this function from Underscore (which you'll also find in older versions of Lodash) is [`_.object`](https://underscorejs.org/#object). – Julian May 22 '21 at 17:14
  • Include the whole lib just for this? Rolling it myself does not pull in tons of unused code. – live627 Feb 11 '23 at 10:38
19

As an alternate solution, not already mentioned I think :

const keys = ["height", "width"];
const values = ["12px", "24px"];
const result = {};

keys.forEach((key, idx) => result[key] = values[idx]);
console.log(result);
isherwood
  • 58,414
  • 16
  • 114
  • 157
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
13

You can combine two arrays with map method, then convert it with Object.fromEntries.

var keys = ["height", "width"];
var values = ["12px", "24px"];

var array = keys.map((el, i) => {
  return [keys[i], values[i]];
});
// → [["height", "12px"], ["width", "24px"]]

var output = Object.fromEntries(array);
// → {height: "12px", width: "24px"}
console.log(output);
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
7

A functional approach with immutability in mind:

const zipObj = xs => ys => xs.reduce( (obj, x, i) => ({ ...obj, [x]: ys[i] }), {})

const arr1 = ['a', 'b', 'c', 'd']
const arr2 = ['e', 'f', 'g', 'h']

const obj = zipObj (arr1) (arr2) 

console.log (obj)
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
4

You could use a reduce() function to map the key-value pairs to an object.

/**
 *  Apply to an existing or new object, parallel arrays of key-value pairs.
 *
 *  @param   {string[]} keys      - List of keys corresponding to their accociated values.
 *  @param   {object[]} vals      - List of values corresponding to their accociated keys.
 *  @param   {object}   [ref={}]  - Optional reference to an existing object to apply to.
 *
 *  @returns {object} - The modified or new object with the new key-value pairs applied.
 */
function toObject(keys, vals, ref) {
  return keys.length === vals.length ? keys.reduce(function(obj, key, index) {
    obj[key] = vals[index];
    return obj;
  }, ref || {}) : null;
}

var keys   = [ "height" , "width" ];
var values = [ "12px"   , "24px"  ];

document.body.innerHTML = '<pre>' + JSON.stringify(toObject(keys, values), null, 2) + '</pre>';
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
4

Now we have Object.fromEntries we can do something like that:

const keys = [ "height", "width" ];
const values = [ "12px", "24px" ];
const myObject = Object.fromEntries(
    values.map((value, index) => [keys[index], value])
);

console.log(myObject);
Moshe Harush
  • 671
  • 6
  • 20
3

Here's an example with all consts (non-modifying) and no libraries.

const keys = ["Adam", "Betty", "Charles"];
const values = [50, 1, 90];
const obj = keys.reduce((acc, key, i) => {
  acc[key] = values[i];
  return acc;
}, {});
console.log(obj);

Alternatively, if you'd consider libraries you could use lodash zipobject which does just what you asked.

darkhipo
  • 1,384
  • 1
  • 14
  • 19
2

You could transpose the arrays and get the object with the entries.

const
    transpose = (r, a) => a.map((v, i) => [...(r[i] || []), v]),
    keys = [ "height", "width" ],
    values = [ "12px", "24px" ],
    result = Object.fromEntries([keys, values].reduce(transpose, []));

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1
function combineObject( keys, values)
{
    var obj = {};
    if ( keys.length != values.length)
       return null;
    for (var index in keys)
        obj[keys[index]] = values[index];
     return obj;
};


var your_obj = combine( your_keys, your_values);
Artem Barger
  • 40,769
  • 9
  • 59
  • 81
  • heh, i saw you fixed it so removed the comment, which you then responded to -- hurrah for async conversation :D You should also avoid new Object as Object may be changed, but {} is spec'd as using the original Object constructor. – olliej Jul 13 '09 at 06:30
  • The function is still incorrect. combineObject(["height", "width"], ["12px", "24px"]).height incorrectly returns "24px". – Simon Lieschke Jul 13 '09 at 06:36
  • Thanks I've fixed it according to your comment, but I'm not sure that can be an issue, since once somebody changes the Object it's on purpose so maybe it better to be implied on all objects you will have. – Artem Barger Jul 13 '09 at 06:37
1

Here's one which will transform nested arrays into an array of multiple key-value objects.

var keys = [
  ['#000000', '#FFFFFF'],
  ['#FFFF00', '#00FF00', '#00FFFF', '#0000FF'],
];
var values = [
  ['Black', 'White'],
  ['Yellow', 'Green', 'Cyan', 'Blue'],
];
const zipObj = xs => ys => xs.reduce( (obj, x, i) => ({ ...obj, [x]: ys[i] }), {})
var array = keys.map((el, i) => zipObj (keys[i]) (values[i]));

console.log(array);

Output is

[
  {
    "#000000": "Black",
    "#FFFFFF": "White"
  },
  {
    "#FFFF00": "Yellow",
    "#00FF00": "Green",
    "#00FFFF": "Cyan",
    "#0000FF": "Blue"
  }
]
live627
  • 397
  • 4
  • 18
0

Providing a solution with a for...of loop.

var keys = ["height", "width"];
var values = ["12px", "24px"];
const result = {};
for (let [index, key] of keys.entries())
  result[key] = values[index];
console.log(result);
You can also use a library like ramda which has zipObj function. Example:
const keys = ["height", "width"];
const values = ["12px", "24px"];
const result = R.zipObj(keys, values);
console.log(result);
varad_s
  • 764
  • 1
  • 12
  • 24
-1

In the jQuery-Utils project, the ArrayUtils module has a zip function implemented.

//...
zip: function(object, object2, iterator) {
    var output = [];
    var iterator = iterator || dummy;
        $.each(object, function(idx, i){
        if (object2[idx]) { output.push([i, object2[idx]]); }
    });
    return output;
}
//...
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838