Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transform an array in to another array

I nave an array:

const arr = [
  { name: "aa", type: "total", count: 28394 },
  { name: "aa", type: "featured", count: 4 },
  { name: "aa", type: "noAnswers", count: 5816 },
  { name: "ba", type: "total", count: 148902 },
  { name: "ba", type: "featured", count: 13 },
  { name: "ba", type: "noAnswers", count: 32527 },
  { name: "cc", type: "total", count: 120531 },
  { name: "cc", type: "featured", count: 6 },
  { name: "cc", type: "noAnswers", count: 24170 }
];


const arrResult = [
  { name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
  { name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
  { name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];

I come up with this code:

let output = [];

const unique = [...new Set(arr.map(item => item.name))];

for(const key of unique) {
  let result = arr.filter(x => {
    return x.name === key;
  });
  output.push({
    name: key,
    // need to get the rest of the properties here
    // total
    // featured
    // noAnswers
  });
}

The only one thing I can not figure out is how to get the property names. Any ideas?

like image 262
sreginogemoh Avatar asked Jan 26 '23 21:01

sreginogemoh


1 Answers

You can try something like this:

Idea:

  • Create a hashMap so you can group objects via name.
  • Then, add necessary properties to this group.
  • Finally, loop over keys and create final object with name property added back.

const arr = [ { name: "aa", type: "total", count: 28394 }, { name: "aa", type: "featured", count: 4 }, { name: "aa", type: "noAnswers", count: 5816 }, { name: "ba", type: "total", count: 148902 }, { name: "ba", type: "featured", count: 13 }, { name: "ba", type: "noAnswers", count: 32527 }, { name: "cc", type: "total", count: 120531 }, { name: "cc", type: "featured", count: 6 }, { name: "cc", type: "noAnswers", count: 24170 } ];

const hashMap = arr.reduce((acc, item) => {
  acc[item.name] = acc[item.name] || {};
  acc[item.name][item.type] = item.count;
  return acc;
}, {});

const result = Object.keys(hashMap).map((name) => Object.assign({}, {name}, hashMap[name] ));

console.log(result)

Working:

What I'm doing is I'm creating a new object for every new name. So, this: acc[item.name] = acc[item.name] || {}; checks if the entry is unavailable or not.

  • If unavailable, return a new object.
  • If available, return same object's reference.

So for any given name, you will only refer to same object.

Now this: acc[item.name][item.type] = item.count sets the properties. As we are referring to same object, you are setting property in one place. So if you have duplicate entries, say

[
    { name: "aa", type: "total", count: 28394 },
    { name: "aa", type: "total", count: 123},
]

output will have total: 123 instead.

So, at the end, you have a structure like:

{
  aa: {
    total: <something>,
    feature: <something>,
    ...
  }
}

Now all you have to do is merge the name in this object and return the value. You can also create the object with name property as default (as done by adiga). Thats something I didn't think while answering. So crediting instead of answering.

like image 134
Rajesh Avatar answered Feb 05 '23 02:02

Rajesh