Turn array of objects into an object

Viewed 163

I have an array of branches that looks roughly like this:

let branches = [
  {
    id: 21,
    name: "Branch 1",
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  {
    id: 22,
    name "Branch 2"
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  // .. etc
]

But I'd like to turn it into an object with the name as the key for each.

Desired output:

branches = {
  "Branch 1": {
    id: 21,
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  "Branch 2": {
    id: 22,
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  }
}

Tried:

let newBranches = branches.map(branch => (
  {
    [branch.name]: {
      id: branch.id,
      days: branch.opening_times
    }
  }
));
console.log(newBranches)

But of course mapping gives me an array output:

[
  0: {Branch 1: {…}}
  1: {Branch 2: {…}}
]

Can anyone help point me in the right direction to get a new object with the name key as an object itself?

7 Answers

With a simple reduce() operation and object destructuring:

const branches = [{
    id: 21,
    name: "Branch 1",
    opening_times: []
  },
  {
    id: 22,
    name: "Branch 2",
    opening_times: []
  }
];

const result = branches.reduce((a, {name, ...v}) => (a[name] = v, a), {});

console.log(result);

I'd just use a simple for-of loop. You'll get reduce answers, but all reduce does here is add complexity.

const result = {};
for (const {name, id, opening_times} of branches) {
  result[name] = {id, opening_times};
}

Live Example:

let branches = [
  {
    id: 21,
    name: "Branch 1",
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  {
    id: 22,
    name: "Branch 2",
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  // .. etc
];
const result = {};
for (const {name, id, opening_times} of branches) {
  result[name] = {id, opening_times};
}
console.log(result);
.as-console-wrapper {
    max-height: 100% !important;
}


Adding in Code Maniac's suggestion of using rest:

const result = {};
for (const {name, ...entry} of branches) {
  result[name] = entry;
}

Live Example:

let branches = [
  {
    id: 21,
    name: "Branch 1",
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  {
    id: 22,
    name: "Branch 2",
    opening_times: [ {}, {}, {} ] // Array of objects (Monday, Tuesday etc)
  },
  // .. etc
];
const result = {};
for (const {name, ...entry} of branches) {
  result[name] = entry;
}
console.log(result);
.as-console-wrapper {
    max-height: 100% !important;
}

Those are slightly different, in that the first one explicitly only uses id and opening_times in the result, but the rest version uses all properties other than name. And of course, there's a difference in readability (explicit vs. implicit), but there are places I'd use each of them.

You could assign all object by spreading new object with the wanted key of name and the rest of the object.

let branches = [{ id: 21, name: "Branch 1", opening_times: [{}, {}, {}] }, { id: 22, name: "Branch 2", opening_times: [{}, {}, {}] }],
    newBranches = Object.assign({}, ...branches.map(({ name, ...o }) => ({ [name]: o })));

console.log(newBranches);
.as-console-wrapper { max-height: 100% !important; top: 0; }

With (upcoming) Object.fromEntries

let branches = [{ id: 21, name: "Branch 1", opening_times: [{}, {}, {}] }, { id: 22, name: "Branch 2", opening_times: [{}, {}, {}] }],
    newBranches = Object.fromEntries(branches.map(({ name, ...o }) => [name, o]));

console.log(newBranches);
.as-console-wrapper { max-height: 100% !important; top: 0; }

ES 2019 draft provides Object.fromEntries for this exact purpose:

result = Object.fromEntries(branches.map(({name,...rest}) => [name, rest]))

It's already implemented in most browsers, but the polyfill is easy:

Object.fromEntries = iter =>
    Object.assign({},
        ...[...iter].map(
            ([k, v]) => ({[k]: v})
        ));

You can use reduce.

let branches = [{id:21,name:"Branch 1",opening_times:[{},{},{}]},{id:22,name:"Branch 2" ,opening_times:[{},{},{}]}];
const res = branches.reduce((acc, { name, ...rest }) => (acc[name] = { ...rest }, acc), {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }

ES5 syntax:

var branches = [{id:21,name:"Branch 1",opening_times:[{},{},{}]},{id:22,name:"Branch 2" ,opening_times:[{},{},{}]}];
var res = branches.reduce(function(acc, curr) {
  acc[curr.name] = { id: curr.id, opening_times: curr.opening_times };
  return acc;
}, {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }

let branches = [{
    id: 21,
    name: "Branch 1",
    opening_times: [{}, {}, {}] // Array of objects (Monday, Tuesday etc)
  },
  {
    id: 22,
    name: "Branch 2",
    opening_times: [{}, {}, {}] // Array of objects (Monday, Tuesday etc)
  }
]

let newBranches = {};

branches.forEach((el) => {
  newBranches[el.name] = {
    id: el.id,
    opening_times: el.opening_times
  };
});

console.log(newBranches)

You could try this (ES6)

Object.assign({}, ...array.map(item => ({ [item.name]: item })));
Related