80

I have an array:

[ [ 'cardType', 'iDEBIT' ],
  [ 'txnAmount', '17.64' ],
  [ 'txnId', '20181' ],
  [ 'txnType', 'Purchase' ],
  [ 'txnDate', '2015/08/13 21:50:04' ],
  [ 'respCode', '0' ],
  [ 'isoCode', '0' ],
  [ 'authCode', '' ],
  [ 'acquirerInvoice', '0' ],
  [ 'message', '' ],
  [ 'isComplete', 'true' ],
  [ 'isTimeout', 'false' ] ]

But I can't access data via an array's key, e.g. arr['txnId'] does not return 20181. How can I convert the above array of tuples into an object, so that I can easily access data by key.

royhowie
  • 11,075
  • 14
  • 50
  • 67
Anthony
  • 13,434
  • 14
  • 60
  • 80

14 Answers14

101

As baao notes, since 2019 you can use Object.fromEntries(arr) (docs) to do exactly this on all modern browsers:

var arr = [['cardType', 'iDEBIT'],
  ['txnAmount', '17.64'],
  ['txnId', '20181']];

console.log(Object.fromEntries(arr));

If that’s not available, my previous solution was to map to an array of key-value objects and combine the objects by spreading into Object.assign:

Object.assign(...arr.map(([key, val]) => ({[key]: val})))
Toph
  • 2,561
  • 2
  • 24
  • 28
  • 2
    [Computed property names](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015) are also used in `{[d[0]]: d[1]}` :) – Chalk Oct 06 '16 at 11:42
  • 4
    `Object.assign.apply(null, arr.map(([key, val]) => { return { [key]: val } }))` is a little easier to read and understand (when spread onto multiple lines). – royhowie Jul 18 '17 at 18:22
  • What are the dots ...? – ctrl-alt-delor Oct 14 '17 at 15:26
  • @ctrl-alt-delor That’s the new-ish “spread operator” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator. Here it turns the array of one-key objects `[{cardType: 'iDEBIT'}, {txnAmount: '17.64'}, {txnId: '20181'}]` into a list of arguments for Object.assign, so it works like `Object.assign({cardType: 'iDEBIT'}, {txnAmount: '17.64'}, {txnId: '20181'})`, which copies all the later values onto the first object, returning the combined object. – Toph Oct 16 '17 at 15:55
  • 1
    A similar one-liner (with reduce) which has the advantage of being more chainable: `arr.reduce((obj, d) => Object.assign(obj, {[d[0]]: d[1]}), {})` – Toph Jan 10 '18 at 15:41
  • @ctrl-alt-delor that is the spread operator in ES6: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – Gabriel Kohen Oct 04 '18 at 17:38
  • 1
    `Object.assign(...array.map( ([key, val]) => ({ [key]: val }) ))` — An integration of @Toph's answer and @royhowie's comment. – ooo Mar 03 '19 at 08:53
62

Update June 2020

ECMAScript 2021 brings Object.fromEntries which does exactly the requirement:

const array =    [ [ 'cardType', 'iDEBIT' ],
      [ 'txnAmount', '17.64' ],
      [ 'txnId', '20181' ],
      [ 'txnType', 'Purchase' ],
      [ 'txnDate', '2015/08/13 21:50:04' ],
      [ 'respCode', '0' ],
      [ 'isoCode', '0' ],
      [ 'authCode', '' ],
      [ 'acquirerInvoice', '0' ],
      [ 'message', '' ],
      [ 'isComplete', 'true' ],
      [ 'isTimeout', 'false' ] ];
      
const obj = Object.fromEntries(array);
console.log(obj);

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries

This will do it:

const array =    [ [ 'cardType', 'iDEBIT' ],
      [ 'txnAmount', '17.64' ],
      [ 'txnId', '20181' ],
      [ 'txnType', 'Purchase' ],
      [ 'txnDate', '2015/08/13 21:50:04' ],
      [ 'respCode', '0' ],
      [ 'isoCode', '0' ],
      [ 'authCode', '' ],
      [ 'acquirerInvoice', '0' ],
      [ 'message', '' ],
      [ 'isComplete', 'true' ],
      [ 'isTimeout', 'false' ] ];
    
var obj = {};
array.forEach(function(data){
    obj[data[0]] = data[1]
});
console.log(obj);

baao
  • 71,625
  • 17
  • 143
  • 203
45

A more idiomatic approach would be to use Array.prototype.reduce:

var arr = [
  [ 'cardType', 'iDEBIT' ],
  [ 'txnAmount', '17.64' ],
  [ 'txnId', '20181' ],
  [ 'txnType', 'Purchase' ],
  [ 'txnDate', '2015/08/13 21:50:04' ],
  [ 'respCode', '0' ],
  [ 'isoCode', '0' ],
  [ 'authCode', '' ],
  [ 'acquirerInvoice', '0' ],
  [ 'message', '' ],
  [ 'isComplete', 'true' ],
  [ 'isTimeout', 'false' ]
];

var obj = arr.reduce(function (o, currentArray) {
  var key = currentArray[0], value = currentArray[1]
  o[key] = value
  return o
}, {})

console.log(obj)
document.write(JSON.stringify(obj).split(',').join(',<br>'))

This is more visually appealing, when done with ES6 (rest parameters) syntax:

let obj = arr.reduce((o, [ key, value ]) => {
    o[key] = value
    return o
}, {})
royhowie
  • 11,075
  • 14
  • 50
  • 67
  • 4
    cleaner way to avoid param reassign `const obj = arr.reduce((obj, [ key, value ]) => { return { ...obj, [key]: value }; }, {});` – huygn Jan 09 '17 at 08:41
  • 1
    Or even avoid the return statement: `const obj = arr.reduce(obj, [key, value] => ({ ...obj, [key]: value }), {})` – Nils Magne Lunde Jan 09 '18 at 08:57
34

Use Map.

new Map(array);

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

This works because the type of your variable array is Array<[key,value]>. The Map constructor can be initialized with an array of arrays where the first element of the inner arrays is the key and the second is the value.

const array = [
  ['cardType', 'iDEBIT'],
  ['txnAmount', '17.64'],
  ['txnId', '20181'],
  ['txnType', 'Purchase'],
  ['txnDate', '2015/08/13 21:50:04'],
  ['respCode', '0'],
  ['isoCode', '0'],
  ['authCode', ''],
  ['acquirerInvoice', '0'],
  ['message', ''],
  ['isComplete', 'true'],
  ['isTimeout', 'false']
];

const obj = new Map(array);

console.log(obj.get('txnDate'));
Paolo
  • 20,112
  • 21
  • 72
  • 113
Rick Viscomi
  • 8,180
  • 4
  • 35
  • 50
  • 6
    Don't do this...it's too simple ^^ – kashiraja Dec 06 '17 at 00:10
  • 1
    @Rick I'm confused here. I just tried this in the console: `array = [['a', 1],['b','two'],['c', [3,3,3]]]` and then `obj = new Map(array);`. However, `obj.a` and `obj['a']` are both undefined. So how does this achieve the objective? – abalter Apr 06 '18 at 07:52
  • @abalter See the MDN link in the answer. The Map object provides methods for get/set, as opposed to direct property access with dot or square bracket notation with raw `{a: 1}` style objects. – Rick Viscomi Apr 06 '18 at 21:11
  • 3
    @RickViscomi -- Ok. Did not know about Map object. However, I would say that what most people are looking for is to get a regular JS object. – abalter Apr 07 '18 at 00:52
  • 4
    Not sure what most people are looking for, but the original question is looking for the value `'2015/08/13 21:50:04'` given the property `txnDate` and I think this is the most semantic way to do that. – Rick Viscomi Apr 12 '18 at 03:08
  • @RickViscomi, the question specifies "How to convert an array of key-value tuples into an object" – PA. Oct 25 '20 at 10:30
  • 1
    @PA. `typeof new Map() // "object"` :) – Rick Viscomi Oct 26 '20 at 18:34
  • @RickViscomi tricky :) `typeof { array }` returns "object" as well but it would not qualify as an answer, would it? – PA. Oct 26 '20 at 18:35
  • 1
    If someone can find a way to answer the question using an Array, sure. The way I approach StackOverflow is to answer the intent of the question and not necessarily to restrict myself to the semantics of how the question was asked. Sometimes the asker doesn't even know what's possible so they're unable to ask for it specifically. – Rick Viscomi Oct 27 '20 at 20:24
15
arr.reduce((o, [key, value]) => ({...o, [key]: value}), {})
Oswaldo
  • 3,296
  • 4
  • 25
  • 35
8

With Object.fromEntries, you can convert from Array to Object:

var entries = [
  ['cardType', 'iDEBIT'],
  ['txnAmount', '17.64'],
  ['txnId', '20181'],
  ['txnType', 'Purchase'],
  ['txnDate', '2015/08/13 21:50:04'],
  ['respCode', '0'],
  ['isoCode', '0'],
  ['authCode', ''],
  ['acquirerInvoice', '0'],
  ['message', ''],
  ['isComplete', 'true'],
  ['isTimeout', 'false']
];
var obj = Object.fromEntries(entries);
console.log(obj);
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
  • 1
    This is pretty cool, just be aware that as of writing this its status is: Draft. And the comment is: Initial definition in ECMAScript 2019. – Joseph Connolly Jul 31 '19 at 19:59
3

use the following way to convert the array to an object easily.

var obj = {};
array.forEach(function(e){
   obj[e[0]] = e[1]
})

This will use the first element as the key and the second element as the value for each element.

Imesh Chandrasiri
  • 5,558
  • 15
  • 60
  • 103
3

ES5 Version using .reduce()

const object = array.reduce(function(accumulatingObject, [key, value]) {
  accumulatingObject[key] = value;
  return accumulatingObject;
}, {});
sudo soul
  • 1,504
  • 13
  • 20
  • How do I use this? Sorry, javascript newb, not sure how to call this? – Paul Kenjora Apr 30 '20 at 19:10
  • @PaulKenjora Where it says `const object = array.reduce` ... `array` is the name of the variable with the original array, and `object` is the name of the variable you are assigning the new value to. It's already being called, and assigning the value to a new variable `object`. – sudo soul May 01 '20 at 21:06
2

Short ES6 way with Airbnb code style

Exemple:

const obj = arr.reduce((prevObj, [key, value]) => ({ ...prevObj, [key]: value }), {});
A. Moynet
  • 450
  • 3
  • 8
2

The new JS API for this is Object.fromEntries(array of tuples), it works with raw arrays and/or Maps

  • 1
    Provide a code sample combining your suggestion with the code from the user that posted the question to make your answer more useful – Keith Dawson Apr 10 '19 at 03:56
1

easiest way to do it where array is of your JSON data :

var obj = {};
array.forEach(function(Data){
obj[Data[0]] = Data[1]
})
Anand Dwivedi
  • 1,452
  • 13
  • 23
1

I much more recommend you to use ES6 with it's perfect Object.assign() method.

Object.assign({}, ...array.map(([ key, value ]) => ({ [key]: value })));

What happening here - Object.assign() do nothing but take key:value from donating object and puts pair in your result. In this case I'm using ... to split new array to multiply pairs (after map it looks like [{'cardType':'iDEBIT'}, ... ]). So in the end, new {} receives every key:property from each pair from mapped array.

Appeiron
  • 1,063
  • 7
  • 14
1

You could do this easily using array reduce in ES6

In this example we create a reducer function and pass an object '{}' as initial value to the reduce function along with the reducer

const arr =    [ [ 'cardType', 'iDEBIT' ],
  [ 'txnAmount', '17.64' ],
  [ 'txnId', '20181' ],
  [ 'txnType', 'Purchase' ],
  [ 'txnDate', '2015/08/13 21:50:04' ],
  [ 'respCode', '0' ],
  [ 'isoCode', '0' ],
  [ 'authCode', '' ],
  [ 'acquirerInvoice', '0' ],
  [ 'message', '' ],
  [ 'isComplete', 'true' ],
  [ 'isTimeout', 'false' ] ];

const reducer = (obj, item) => {
  obj[item[0]] = item[1];
  return obj;
};

const result = arr.reduce(reducer, {});

console.log(result);
0
let obj ={'abc':123,'other':566};

// first way
let coll= Object.entries(obj).map(i=>Object.assign({'key':i[0],'value':i[1]}))

results: coll => 
0: {key: "abc", value: 123}
1: {key: "other", value: 566}

// second way
let coll2= new Map(Object.entries(obj))
results: coll2 =? 
//[[Entries]]
0: {"abc" => 123}
1: {"other" => 566}
Mohamed.Abdo
  • 2,054
  • 1
  • 19
  • 12