0

Let's say I got an Array below:

[
  { type: 'senior', schoolName: 'school-A', country: 'America' },
  { type: 'senior', schoolName: 'school-B', country: 'England' },
  { type: 'junior', schoolName: 'school-C', country: 'German' },
  { type: 'junior', schoolName: 'school-D', country: 'Italy' }, 
]

How can I convert the array above to an object as shown in below:

{
  senior: {
    America: 'school-A', 
    England: 'school-B'
  }, 
  junior: {
    German: 'school-C', 
    Italy: 'school-D'
  }
}

What is the syntactically cleanest way to accomplish this?

Thanks for any help!!

1
  • 1
    What if there are two senior schools in America? Commented Nov 15, 2021 at 11:02

2 Answers 2

5

One way could be to reduce your array of objects to a single object. For each iteration you can accumulate your object (initially starting as an empty object {}), to contain the current type key along with the new key-value pair for the country and schoolName. By using the spread syntax ... you can merge the previously seen object at the type key (from your current accumulated object) with the new object you're constructing.

See code comments in the example below:

const arr = [ { type: 'senior', schoolName: 'school-A', country: 'America' }, { type: 'senior', schoolName: 'school-B', country: 'England' }, { type: 'junior', schoolName: 'school-C', country: 'German' }, { type: 'junior', schoolName: 'school-D', country: 'Italy' }, ];

const res = arr.reduce((acc, {type, schoolName, country}) => ({ // obtain the kys from the current object using destructuring assignment
  ...acc, // merge the current object stored in acc into the current object `{}` we're building
  [type]: { // using "computed property names"
    ...acc[type], // merge inner object (still worrks when acc[type] === undefined) 
    [country]: schoolName
  }
}), {}); // start with an initial empty object `{}` that we'll accumulate to
console.log(res);

Spreading your object each iteration could be seen as inefficient, so you can accumulate the single object reference instead (which at this point, might be worth looking at using a standard for loop for readability instead):

const arr = [ { type: 'senior', schoolName: 'school-A', country: 'America' }, { type: 'senior', schoolName: 'school-B', country: 'England' }, { type: 'junior', schoolName: 'school-C', country: 'German' }, { type: 'junior', schoolName: 'school-D', country: 'Italy' }, ];

const res = arr.reduce((acc, {type, schoolName, country}) => {
  if(!acc[type]) acc[type] = {};
  acc[type][country] = schoolName;
  return acc;
}, {});
console.log(res);

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

Comments

1

I think this is a simple and readable solution to your problem (if multiple instances of the same country show up in the same type the last occurence will override all previous occurences)

let data = [
  { type: 'senior', schoolName: 'school-A', country: 'America' },
  { type: 'senior', schoolName: 'school-B', country: 'England' },
  { type: 'junior', schoolName: 'school-C', country: 'German' },
  { type: 'junior', schoolName: 'school-D', country: 'Italy' }, 
];

let res = {};

data.forEach(e => {
  if(!res[e.type])
    res[e.type] = {};
    
  res[e.type][e.country] = e.schoolName;
});

console.log(res);

1 Comment

Having a for each in this way does produce side-effects, it's manipulates an object outside of it's scope, namely res. Since the OP asked for syntactically cleanest way, I would argue a forEach isn't the best (then again, I voted to close the question as it is opinion based because of that sentence)

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.