Reputation: 2095
First of all, give thanks for reading my question and try to help me and apologize for my English.
My problem is that I would like implement a nice solution, using less arrays inside arrays.
I have n arrays with n objects, each object has two properties: name and type. I would like to know how get objects that are in all arrays repeated.
Here is my code:
let arraysNoEmpties = [...res].filter(array => array.length > 0);
let attributes = arraysNoEmpties[0].map(p => {
return { name: p.name, type: p.type };
});
let items = getAtributeInAllArrays(attributes, arraysNoEmpties);
console.log('items: ', items);
const getAtributeInAllArrays = (properties, list) => {
let items = [];
for (let i = 0; i < properties.length; i++) {
const property = properties[i];
let numTimes = 0;
for (let j = 0; j< list.length; j++) {
const array = list[j];
let propsOfarray = array.map(atr => atr.name);
if (propsOfarray.indexOf(property.name) !== -1) {
numTimes++;
if (numTimes === list.length) {
items.push(property);
}
}
}
}
items.sort((a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0));
return items;
};
Upvotes: 0
Views: 1877
Reputation: 3190
You want to filter each object that isn't found in each array provided.
We can make use of the some
and every
functions to achieve this:
let arrays = [[{name:"1"}, {name:"2"}], [{name:"1"}]]
let objects = [{name:"1"}, {name:"2"}] // only the first object is found in each array
const objectsInEachArray = objects.filter(o => arrays.every(arr => arr.some(r => r.name == o.name && r.type == o.type)))
Lets break that down:
To check if an object is contained in an array we can use the array.some()
function. Here we return a boolean to declare a match or not. In this case I guess you want to check each property. Here you could either do a full equality check (deep or shallow) or, in simple cases like this one just explicitly check each property:
arr.some(r => r.name == o.name && r.type == o.type)
Since we have multiple arrays and the requirement is that the object should be found at least once in each of them we must call the every method on the 2 dimensional array:
arrays.every(arr => arr.some(r => r.name == o.name && r.type == o.type))))
Since we have multiple objects and want the result to be an array with only matching objects we call filter on the object array.
objects.filter(o => arrays.every(arr => arr.some(r => r.name == o.name && r.type == o.type)))))
objectsInEachArray
now only contains objects that are found in each second level array from arrays
Therefore:
console.log(objectsInEachArray) -> [{name: "1"}]
Upvotes: 2
Reputation: 6145
If your arrays will be similar lengths, or all very small (<~20 elements), you could use something like this. Modify the predicate
function to specify the criteria for two objects matching. For instance, if you add another element or decide name
is unique even without type
.
function commonElements(arrays...) {
const predicate = (obj1, obj2) => {
return obj1.name == obj2.name && obj1.type == obj2.type;
};
return arrays[0].filter(e1 => !arrays.map(array => array.map(e2 => predicate(e1, e2)).includes(true)).includes(false));
}
If you’re likely to have some significantly longer arrays, first select the shortest one to use as the basis of the filter:
function commonElements(arrays...) {
const predicate = (obj1, obj2) => {
return obj1.name == obj2.name && obj1.type == obj2.type;
};
const lengths = arrays.map(arr => arr.length);
const shortestArray = arrays[lengths.indexOf(lengths.sort((a, b) => a - b)[0])];
return shortestArray.filter(e1 => !arrays.map(array => array.map(e2 => predicate(e1, e2)).includes(true)).includes(false));
}
The last line of both examples is essentially the same, and looks like this in slightly longer form:
shortestArray.filter(e1 => {
return !arrays.map(array => {
return array.map(e2 => {
return predicate(e1, e2);
}).includes(true);
}).includes(false);
});
For each element of the filter array, it’s compared against every element in each other array using the predicate
function. If at least one element matches (.includes(true)
), that array is mapped to true
. If every array maps to true
(! (...) .includes(false)
), the element is accepted by the .filter(...)
.
Upvotes: 1