Destructure array to object property keys
Asked Answered
I

9

42

I have an array of values like:

const arr = [1,2,3];

Is there any way I can use destructuring to create the following output? If not, what is the easiest way I can do this in ES6 (or later)?

const obj = {
    one: 1,
    two: 2,
    three: 3
};

I tried this, but I guess it doesn't work as this is the syntax for computed keys:

const arr = [1,2,3];
const obj = {
  [one, two, three] = arr
};
Insolate answered 7/7, 2016 at 10:5 Comment(4)
The original purpose of destructuring is to extract values from data stored in (nested) objects/arrays. In your example you create an object. An object literal fits better in this case.Bounty
Using computed properties would actually cause the inverse of the usual problem. Normally when people want to use a variable as an object literal key, it is seen as a prop. Here you want to define a prop, but it would be seen as a variable (if that syntax was allowed). Or at least it would be ambiguous when there's only one in the brackets.Wilmawilmar
@squint Indeed, that's why I was kind of hoping for a syntax which uses destructuring rather than computed properties, but it doesn't look like that's possible. I guess it makes sense given the longform is really not too much longer, just repetitive.Insolate
It does look like a compelling syntax, except for the ambiguity of { [foo]: ["bar"] }, which would have to be handled as an unfortunate special case.Wilmawilmar
S
14

I don't believe there's any structuring/destructuring solution to doing that in a single step, no. I wanted something similar in this question. The old := strawman proposal doesn't seem to have legs in the new proposal list, so I don't think there's much activity around this right now.

IMHO, this answer is the best one here (much better than this one). Two steps, but concise and simple.

But if it's two steps, you could also use a simple object initializer:

const arr = [1,2,3];
const obj = {
  one: arr[0],
  two: arr[1],
  three: arr[2]
};
console.log(obj);

Another option is to do it with several temporary arrays but technically only one statement (I am not advocating this, just noting it):

const arr = [1,2,3];
const obj = Object.fromEntries(
    ["one", "two", "three"].map((name, index) =>
        [name, arr[index]]
    )
);
console.log(obj);
Swearword answered 7/7, 2016 at 10:11 Comment(4)
There is a almost one-step solution without creating unnecessary variables.Bounty
@LUH3417: "almost one-step" = "two-step". :-) But yes, that's another perfectly-valid approach.Swearword
it appears you can actually destructure onto object properties, see https://mcmap.net/q/382896/-destructure-array-to-object-property-keys or https://mcmap.net/q/382896/-destructure-array-to-object-property-keys belowChateau
@lohfu - Yes, you can (in fact, I linked to a solution that does in the answer). You can destructure into anything assignable. But it's still two steps.Swearword
B
47

You can assign destructured values not only to variables but also to existing objects:

const arr = [1,2,3], o = {};    
({0:o.one, 1:o.two, 2:o.three} = arr);

This works without any additional variables and is less repetitive. However, it also requires two steps, if you are very particular about it.

Bounty answered 7/7, 2016 at 11:43 Comment(7)
This is terrifying and amazing at the same time.Goodwill
In TypeScript, I get an error here. It says: Block scoped variables cannot be redeclaredSunshade
@Sunshade - It shouldn't, and doesn't for me. You do have to give o a type (otherwise, it doesn't have one, two, or three properties).Swearword
Here is a live demoJackinthepulpit
One line version: const obj = (o = {}, [o.one, o.two, o.three] = arr, o)Ody
@FabianoTaioli: pretty cool, too bad it creates a global o variableReorganize
Damn, this JavaScript is amazing :) @FabianoTaioli , this global o var is just for a presentation purposes in this particular case. I think this approach is more for if you have some object, and you want to extend it destructing more items directly in it.Alleviative
U
22

With destructuring, you can either create new variables or assign to existing variables/properties. You can't declare and reassign in the same statement, however.

const arr = [1, 2, 3],
    obj = {};

[obj.one, obj.two, obj.three] = arr;
console.log(obj);
// { one: 1, two: 2, three: 3 }
Unfortunate answered 21/3, 2018 at 18:6 Comment(2)
This is the best answer IMHO.Swearword
This does not work in TypeScript. Any solutions for this?Argot
S
14

I don't believe there's any structuring/destructuring solution to doing that in a single step, no. I wanted something similar in this question. The old := strawman proposal doesn't seem to have legs in the new proposal list, so I don't think there's much activity around this right now.

IMHO, this answer is the best one here (much better than this one). Two steps, but concise and simple.

But if it's two steps, you could also use a simple object initializer:

const arr = [1,2,3];
const obj = {
  one: arr[0],
  two: arr[1],
  three: arr[2]
};
console.log(obj);

Another option is to do it with several temporary arrays but technically only one statement (I am not advocating this, just noting it):

const arr = [1,2,3];
const obj = Object.fromEntries(
    ["one", "two", "three"].map((name, index) =>
        [name, arr[index]]
    )
);
console.log(obj);
Swearword answered 7/7, 2016 at 10:11 Comment(4)
There is a almost one-step solution without creating unnecessary variables.Bounty
@LUH3417: "almost one-step" = "two-step". :-) But yes, that's another perfectly-valid approach.Swearword
it appears you can actually destructure onto object properties, see https://mcmap.net/q/382896/-destructure-array-to-object-property-keys or https://mcmap.net/q/382896/-destructure-array-to-object-property-keys belowChateau
@lohfu - Yes, you can (in fact, I linked to a solution that does in the answer). You can destructure into anything assignable. But it's still two steps.Swearword
G
6

Using destructuring assignment it is possible to assign to an object from an array

Please try this example:

const numbers = {};

[numbers.one, numbers.two, numbers.three] = [1, 2, 3]

console.log(numbers)

The credit to the boys of http://javascript.info/ where I found a similar example. This example is located at http://javascript.info/destructuring-assignment in the Assign to anything at the left-side section

Gifu answered 12/9, 2019 at 13:40 Comment(1)
Yes. [numbers.one, numbers.two, numbers.three] = [1, 2, 3] works. but, quite literally, so what? It's MORE characters than just typing out numbers.one=1; numbers.two=2; numbers.three=3;! And LOTS more than just numbers={one:1, two:2, three:3}! Hooray! We've managed to that the terse elegant syntax of destructuring and make it LESS efficient than just doing it the (categorically-readable) vanilla way!Henrieta
T
3

This answers a slightly different requirement, but I came here looking for an answer to that need and perhaps this will help others in a similar situation.

Given an array of strings : a = ['one', 'two', 'three'] What is a nice un-nested non-loop way of getting this resulting dictionary: b = { one : 'one', two: 'two', three: 'three' } ?

const b = a.map(a=>({ [a]: a })).reduce((p, n)=>({ ...p, ...n }),{})

Timbering answered 30/8, 2017 at 4:29 Comment(1)
You can use Object.assign() with the spread syntax instead of .reduce(): const o = Object.assign(...a.map(val => ({ [val]: val })));Callida
O
2

Arrow flavor:

const obj = (([one, two, three]) => ({one, two, three}))(arr)
Ody answered 25/2, 2022 at 8:56 Comment(6)
This is the best answer among all others.Swimming
Alternative: const obj = (one, two, three) => ({one, two, three})(...arr) 😬Unpaged
@FrankN I think additional brackets needed: const obj = ((one, two, three) => ({one, two, three}))(...arr)Ody
just verified, yes you're right!Unpaged
@Swimming WHY!? WHY is it the best answer!? obj = (([param1, param2, param3, param4, param5]) => ({param1, param2, param3, param4, param5}))(arr) requires MORE CODE than just doing it the old annoying way: obj = {param1: arr[1], param2: arr[2], param3: arr[3], param4: arr[4], param5: arr[5]}! Almost 25% more (102 characters vs 86)! Why is this BETTER!? If you still have to type every key out, TWICE, in this case, why is that faster!? Destructuring assignment is to SPEED the workflow. That is the tradeoff to the loss in readability. This makes it slower, longer to type AND harder to read!Henrieta
@Henrieta what if you remove one item one day? Then you need to modify all numbers after the one you deleted.Swimming
S
0

You can achieve it pretty easily using lodash's _.zipObject

const obj = _.zipObject(['one','two','three'], [1, 2, 3]);
console.log(obj); // { one: 1, two: 2, three: 3 }
Spike answered 12/3, 2020 at 14:22 Comment(0)
C
0

let distructingNames = ['alu', 'bob', 'alice', 'truce', 'truce', 'truce', 'truce', 'bob'];
let obj={};
distructingNames.forEach((ele,i)=>{
    obj[i]=ele;
})
console.log('obj', obj)
Checkerberry answered 4/2, 2021 at 7:36 Comment(0)
C
0

One of the easiest and less code way is to destructure the array. Then use such constants to update the object.

const arr = [1, 2, 3];
const [one, two, three] = arr;
const obj = {one, two, three};

console.log(obj);

Notice how I assigned values to the object by such writing the names of the constants one, two, and three. You can do so when the name of the key is the same of the property.

//Instead of writing it like this
const obj = {one: one, two: two, three: three};
Catenane answered 25/1, 2022 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.