sjosen sjosen - 1 month ago 6
Javascript Question

Count duplicates and get unique properties in javascript

I have an array of objects that looks something like this

let myArray = [
{
id:"1",
tool:{
type: 'first',
categories: [
{
id:'4',
name:'Car'
}
]
}
},
{
id:"2",
tool:{
type: 'second',
categories: [
{
id:'4',
name:'Car'
},
{
id:'5',
name:'Plane'
}
]
}
}
];


I wish to pull out some data about the categories. The desired result is an object containing unique id's with name and the count of how many times the name was present.
Something like this:

let categories = {
4: {
name: 'Car',
count: 2
},
5: {
name: 'Plane',
count: 1
},
}


This is what I have so far

let result = {}

let unique = [...new Set(myArray.map((item) => {

return [...new Set(item.tool.categories.map((item) => {


result[item.id] = (result[item.id] || 0) + 1;


}))];


}))];


which gives me

[object Object] {
4: 2,
5: 1
}


jsbin

I'm not an experienced javascripter and it is very possible that these loops in loops are very ineffective so any suggestions are much appreciated.
I expect the array to have a max of 1000 object.

/ j

Question update:
What if I wish to change the output slightly to this:

let categories = [
{
id: 4,
name: 'Car',
count: 2
},
{
id: 5,
name: 'Plane',
count: 1
},
]


this is what I have so far:

const count = myArray.reduce((count, obj) => {
obj.tool.categories.forEach(({ id, name }) => {
count[id] = count[id] || { count: 0, name, id };
count[id].count++;
});

return count;
}, {});

console.log(count);

Answer

You could use just the result set as object for counting.

let myArray = [{ id: "1", tool: { type: 'first', categories: [{ id: '4', name: 'Car' }] } }, { id: "2", tool: { type: 'second', categories: [{ id: '4', name: 'Car' }, { id: '5', name: 'Plane' }] } }],
    categories = myArray.reduce((r, a) =>
        (a.tool.categories.forEach(b =>
            (r[b.id] = r[b.id] || { name: b.name, count: 0 }).count++), r), {});

console.log(categories);

Proposal for extended question.

let myArray = [{ id: "1", tool: { type: 'first', categories: [{ id: '4', name: 'Car' }] } }, { id: "2", tool: { type: 'second', categories: [{ id: '4', name: 'Car' }, { id: '5', name: 'Plane' }] } }],
    categories = myArray.reduce((map =>
        (r, a) =>
            (a.tool.categories.forEach(b =>
                (!map.has(b.id) && map.set(b.id, r[r.push({ id: b.id, name: b.name, count: 0 }) - 1]), map.get(b.id).count++)), r))(new Map), []);

console.log(categories);