javaland235
javaland235

Reputation: 803

Getting exact Matching elements between two arrays

I have two arrays as follows:

array1 = [
         {id:1, children: ['a', 'b']},
         {id:2, children: ['a', 'b']},
         {id:3, children: ['b', 'c']},
         {id:4, children: ['c', 'a']},
         {id:5, children: ['a', 'b', 'c']}];

array2 = ['a', 'b'];

Now I want to write a code in JS/TS which will find the exact objects from array1 where every element of children array from array 2 matches exactly with every elements of children array from array 1 (Order doesn't matter).

I have tried to solve this problem with three filters with additional condition of length matching of children array between array 1 and array2. But this also picks up if at least one element gets matched of those children array with desired array length.

I would really appreciate if someone gives me the solution.

array1
.filter(a => a.children
.filter(b => array2
.filter(c => b === c)).length === array2.length);

Edit:

I had actually simplified the problem a bit in the above example. In my actual project, the the two arrays are as follows:

 const productOrders: ProductOrder[] =
      [
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 1}}, {subProduct: 
{subProductId: 2}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 2}}, {subProduct: 
{subProductId: 1}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 2}}, {subProduct: 
{subProductId: 3}}]
        },
        {
          productId: 1, subProductOrders:
            [{subProduct: {subProductId: 1}}, {subProduct: 
{subProductId: 2}}, {subProduct: {subProductId: 3}}]
        },
      ];

    const matchingCriteria: SubProductOrder[] =
      [
        [{subProduct: {subProductId: 1}}, {subProduct: {subProductId: 
2}}]

      ];

Now I want to find the products from the productOrders array where subProductId of the subProductOrders array matches with the subProductId of the matchingCriteria Array (Order doesn't matter). In the above example, the first two products of the productOrders Array should match despite unordered subProductsIds

Upvotes: 3

Views: 191

Answers (4)

Nina Scholz
Nina Scholz

Reputation: 386670

You could take a Set and check the children against this structure.

var array1 = [{ id: 1, children: ['a', 'b'] }, { id: 2, children: ['a', 'b'] }, { id: 3, children: ['b', 'c'] }, { id: 4, children: ['c', 'a'] },  { id: 5, children: ['a', 'b', 'c'] }],
    array2 = ['a', 'b'],
    set2 = new Set(array2),
    result = array1.filter(({ children }) =>
        children.length === set2.size && children.every(Set.prototype.has, set2));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

For a more complex data structure, you could destructure the needed parts and check against a set of subProductId.

const
    getId = ({ subProduct: { subProductId } }) => subProductId;

var productOrders = [{ productId: 1, subProductOrders: [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 1 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 3 } }] }, { productId: 1, subProductOrders: [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }, { subProduct: { subProductId: 3 } }] }],
    matchingCriteria = [{ subProduct: { subProductId: 1 } }, { subProduct: { subProductId: 2 } }],
    set2 = new Set(matchingCriteria.map(getId)),
    result = productOrders.filter(({ subProductOrders }) =>
        subProductOrders.length === set2.size &&
        subProductOrders.every(o => set2.has(getId(o)))
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 4

Alan Omar
Alan Omar

Reputation: 4227

You are filtering array1 elements based on the equality of element.children to array2. so i encourage you to take a look at these answers. as it discuss the equality of two arrays in javascript.

and modify the following code to your needs, this is just one of the easiest options available:

array1.filter((element,index) => {
      return JSON.stringify(element.children) === JSON.stringify(array2)
})

Upvotes: -1

Jacek Rojek
Jacek Rojek

Reputation: 1122

array1 = [
         {id:1, children: ['a', 'b']},
         {id:2, children: ['b', 'a']},
         {id:3, children: ['b', 'c']},
         {id:4, children: ['c', 'a']},
         {id:5, children: ['a', 'b', 'c']}];

array2 = ['a', 'b'];

const x = array1
  .map(a => a.children.sort())
  .filter(a => a.length === array2.length)
  .map(a => a.sort())
  .filter(a => JSON.stringify(a)==JSON.stringify(array2))

console.log(x)

Upvotes: 0

charlietfl
charlietfl

Reputation: 171689

You can use Array#every() and length in a single filter

const arr1 = [
   {id:1, children: ['a', 'b']},
   {id:2, children: ['a', 'b']},
   {id:3, children: ['b', 'c']},
   {id:4, children: ['c', 'a']},
   {id:5, children: ['a', 'b', 'c']}
];


const arr2 = ['a', 'b'];

const matched = arr1.filter(({children: c}) => c.length === arr2.length && arr2.every(v => c.includes(v)))

console.log(matched)

Upvotes: 1

Related Questions