3

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 7

6

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);

Sign up to request clarification or add additional context in comments.

6 Comments

Why not just a[name] = v?
@adiga OP indicates that the name property should not be in the value object.
I meant (a[name] = v, a) instead of (a[name] = {...v}, a)
@adiga I know what you meant. Doing it that way would include the name property in the value object.
But destructuring already takes care of that right? v is already a new object without a name property. {...v} is just cloning v
|
5

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.

5 Comments

Love the readability compared to the reduce methods. Any idea which would be faster though?
On side note:- i guess we can use rest parameter here instead of taking all the properties out and than creating object again, i.e for (const {name, ...rest} of branches)
@EliNathan - On modern JavaScript engines I expect it's a wash. for-of creates and uses an iterator (subject to optimization, which JavaScript engines can definitely do), which involves function calls. reduce doesn't use an iterator, but has calls to the callback. So...
@EliNathan - And of course, you'd have to have at least tens of thousands of entries in branches for it to matter (or you'd have to be doing this over and over again in a tight loop).
Actually going to use the explicit versions here as I simplified the branches array down for the purposes of this question. It has a lot of stuff in it that I don't need to add into my new object. Thanks!
4

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; }

3 Comments

Why your every answer is so complicated? ,A new user who just understands the for loop won't even have a slight idea what's going here,can you just bit more simplify things.
@Shubh I've been seeing Nina Scholz's answers for a couple of years now, and they are consistently the best performing, and often the most creative solutions for any given problem. Stack Overflow does not only aim to be a knowledge repository for beginners.
@RobbyCornelissen,yeah same here but I guess there should be some bit elaboration or some helper links to the new fellow users ,that just widens the horizon for understanding.
4

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})
        ));

1 Comment

You need to remove name property from value, to match expected output
2

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; }

Comments

1

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)

1 Comment

I guess ,its never a good idea to define a global variable and change its value in a loop ,that may cause wrong outputs if we have a complicated code structure
1

You could try this (ES6)

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.