Reputation: 803
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
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
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
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
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