How can I compare multiple arrays of objects and add new properties with the number of occurrences an object was found and the array indexes where the object was found?
The object comparison must be made by the name
property.
Example:
var arrays = [
[
{
name: 'aa',
value: 1
},
{
name: 'ab',
value: 2
},
{
name: 'ac',
value: 3
},
{
name: 'aa',
value: 1
}
],
[
{
name: 'aa',
value: 1
},
{
name: 'ab',
value: 2
},
],
[
{
name: 'ac',
value: 3
},
{
name: 'aa',
value: 1
}
]
]
After execution the object from the above array should have these properties:
[
[
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
},
{
name: 'ab',
value: 2,
occurrences: 2,
where: [0, 1]
},
{
name: 'ac',
value: 3,
occurrences: 2,
where: [0, 2]
},
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
}
],
[
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
},
{
name: 'ab',
value: 2,
occurrences: 2,
where: [0, 1]
}
],
[
{
name: 'ac',
value: 3,
occurrences: 2,
where: [0, 2]
},
{
name: 'aa',
value: 1,
occurrences: 3,
where: [0, 1, 2]
}
]
]
Basically I want to check if the object with a specific name
property exists in the other arrays.
This is the solution that comes in my mind:
1. Loop through the array that has the most objects
2. Loop through each object
3. Loop through the other arrays and apply Array.prototype.find()
But this will take a lot of time since each of my array will have at least 500 objects...
You can use array#reduce
to get the number of occurrences and the index of occurrences in an object.
Then, you can modify your object in the arrays
by simply using Object.assign()
and adding the where
and occurrences
property.
var arrays = [ [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ], [ { name: 'aa', value: 1 }, { name: 'ab', value: 2 }, ], [ { name: 'ac', value: 3 }, { name: 'aa', value: 1 } ] ];
var result = arrays.reduce((res, arr, index) => {
arr.forEach(({name,value}) => {
res[name] = res[name] || {occurrences: 0};
res[name]['where'] = res[name]['where'] || [];
if(!res[name]['where'].includes(index)){
res[name]['where'].push(index);
res[name].occurrences += 1;
}
});
return res;
},{});
arrays.forEach(arr => arr.forEach(obj => Object.assign(obj, result[obj.name])));
console.log(arrays);
This looked like trivial reduce, until i noticed nested arrays ) so it's more like flatten + reduce, with memory.
Code below is doing what you need, just the prop names are short (as i type them on the phone):
let f = (ai, a,v,i,m) => {
if (!a[v.id]) {
a[v.id] = {id: v.id, v: v.name, count: 1, at: [ai]};
} else {
a[v.id].count += 1;
a[v.id].at.push(ai);
}
return a;
};
let r = [[{id: 'aa', value: 42}], [{id: 'ba', value: 11}, {id: 'aa', value: 42}]]
.reduce ((a, v, i) => v.reduce (f.bind (null, i),a), {});
console.log (r);
Code still visits each element in any array only once, so complexity is O(n), and there should not be a problem running it on arrays up to a million of total elements (e.g. 1000 arrays of 1000 elements, or 200 x 5000).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With