Javier
Javier

Reputation: 2095

How check if object exists in multiple arrays

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

Answers (2)

ThatBrianDude
ThatBrianDude

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:

  1. 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)
    
  2. 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))))
    
  3. 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

MTCoster
MTCoster

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

Related Questions