Mohammed Rehan
Mohammed Rehan

Reputation: 61

Reduce a array with reformatting in javascript

I want to reduce the array with only the subject being present in the new object.

array = [{
    subject: "maths",
    credits: 3
  },
  {
    subject: "chemistry",
    credits: 2,
    lab: {
      lab: "chemistry_lab",
      lab_credits: 1,
    },
  }
]

the new object is reformatted and its values are assigned as strings. What's the best way to achieve this

const subject = {
  maths: "",
  chemistry: "",
  chemistry_lab: "",
};

Here's how I tried this but it returns an array of objects, but I want this to be a single object as above

const sub = array.map((op) => {
  const container = {};
  container[op.subject] = "";
  return container;
});

Upvotes: 0

Views: 112

Answers (3)

Zacquio
Zacquio

Reputation: 347

let array = [{
    subject: "maths",
    credits: 3
  },
  {
    subject: "chemistry",
    credits: 2,
    lab: {
      lab: "chemistry_lab",
      lab_credits: 1,
    },
  }
]

let subject = {}
array.forEach(el => {
  subject[el.subject] = ""
  if (el.lab) {
    subject[el.lab.lab] = ""
  }

})

console.log(subject)

// output
// { maths: "", chemistry: "", chemistry_lab: "" }

Upvotes: 1

Shubham J.
Shubham J.

Reputation: 646

var array  = [
            {
                subject: "maths",
                credits: 3
            },
            {
                subject: "chemistry",
                credits: 2,
                lab : {
                    lab: "chemistry_lab",
                    lab_credits: 1,
                },
            }
        ];

var p = array.reduce((acc,i)=>{
acc[i.subject]= '';
if(i.lab){
  acc[i.lab.lab]=''
}
return acc;
},{})

console.log(p)

You can also use JavaScript reduce to achieve the same.

Here's snippet you can try :

var p = array.reduce((acc,i)=>{
acc[i.subject]= '';
if(i.lab){
  acc[i.lab.lab]=''
}
return acc;
},{})

console.log(p)

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50664

Your map method is the right idea, however, it doesn't map the lab objects. You could go for an approach that uses .flatMap() to build an array of [key, value] pairs from each object in your array. By flat-mapping, you can take each subject and lab (if it exists) and "convert" the object into two arrays of key values. You can then filter this mapped array to remove any [key, value] pairs where the key is a falsy value (ie: undefined), and then use Object.fromEntries() on your array of [key, value] pair arrays to build an object for you.

const array = [{ subject: "maths", credits: 3 }, { subject: "chemistry", credits: 2, lab: { lab: "chemistry_lab", lab_credits: 1, }, } ];

const res = Object.fromEntries(array.flatMap(obj => [
  [obj.subject, ''], [obj.lab?.lab, '']
]).filter(([key]) => key));
console.log(res);

Another option could be to remove the .filter(), and perform a check in your .flatMap() function before adding the lab [key, value] pair. This will help you avoid doing an additional iteration on your array:

const array = [{ subject: "maths", credits: 3 }, { subject: "chemistry", credits: 2, lab: { lab: "chemistry_lab", lab_credits: 1, }, } ];

const res = Object.fromEntries(array.flatMap(
  obj => obj.lab?.lab 
    ? [[obj.subject, ''], [obj.lab.lab, '']] 
    : [[obj.subject, '']]
));
console.log(res);

Lastly, a way using .reduce() could look something like this. It builds up an object, adding the subject as a key using computed property names and will add the lab if it exists. It uses the spread syntax to spread the result of curr.lab?.lab && {[curr.lab.lab]: ''}. When cur.lab.lab results in a truthy value, the object is spread and merged into the returned object literal:

const array = [{ subject: "maths", credits: 3 }, { subject: "chemistry", credits: 2, lab: { lab: "chemistry_lab", lab_credits: 1, }, } ];

const res = array.reduce((obj, curr) => ({
  ...obj,
  [curr.subject]: '',
  ...(curr.lab?.lab && {[curr.lab.lab]: ''})
}), {});
console.log(res);

Upvotes: 1

Related Questions