Takebo
Takebo

Reputation: 199

How do i filter an array inside of a array of objects?

I'm trying to filter a list by tags:

const initialState = [
     {id:1 ,name: 'Product A', image: 'pic-001.jpg', tags: ['nature', 'camping', 'outdoor']},
     {id:2 ,name: 'Product B', image: 'pic-002.jpg', tags: ['winter', 'hiking', 'camping', 'snow']},
     {id:3 ,name: 'Product C', image: 'pic-003.jpg', tags: ['vacation', 'family', 'kids', 'river', 'lake', 'fishing']}
   ]

I can filter the list by name using map and filter, my problem is when i try to list the products by tags. Do i have to use foreach inside of my products filter? There's another way of doing it?

Upvotes: 12

Views: 29927

Answers (4)

Ori Drori
Ori Drori

Reputation: 191936

You can create a Set of selected tags, and use Array#some to check if at least one of the tags in the Set exists in the objects' tags list:

const initialState = [
     {id:1 ,name: 'Product A', image: 'pic-001.jpg', tags: ['nature', 'camping', 'outdoor']},
     {id:2 ,name: 'Product B', image: 'pic-002.jpg', tags: ['winter', 'hiking', 'camping', 'snow']},
     {id:3 ,name: 'Product C', image: 'pic-003.jpg', tags: ['vacation', 'family', 'kids', 'river', 'lake', 'fishing']}
];

const filterByTags = ['nature', 'family'];

const filterByTagSet = new Set(filterByTags);

const result = initialState.filter((o) => 
  o.tags.some((tag) => filterByTagSet.has(tag))
);

console.log(result);

Upvotes: 9

sjahan
sjahan

Reputation: 5940

Like that?

const filter = 'nature';
const filteredResult = initialState.filter((item) => {
    return (item.tags.indexOf(filter) >= 0);
});

Upvotes: 16

Calvin
Calvin

Reputation: 149

Firstly to get all the tags and filter the duplicate tags from initialState. Save the array into uniqueTags.

Then compare the uniqueTags with initialState names, to create another array productTags with objects and its properties tags and products.

const initialState = [
     {id:1 ,name: 'Product A', image: 'pic-001.jpg', tags: ['nature', 'camping', 'winter', 'outdoor']},
     {id:2 ,name: 'Product B', image: 'pic-002.jpg', tags: ['winter', 'hiking', 'family', 'camping', 'snow']},
     {id:3 ,name: 'Product C', image: 'pic-003.jpg', tags: ['vacation', 'family', 'kids', 'river', 'lake', 'fishing']}
   ]

   let allTags = [];
   initialState.map((t)=>t.tags).forEach((a)=>a.forEach((b)=>allTags.push(b)))
   let uniqueTags = allTags.filter((a,i,arr)=>arr.indexOf(a,i+1)===-1)


   productTags = [];
   uniqueTags.forEach((u)=>{
       initialState.forEach((t)=>{
           if(t.tags.includes(u))
            productTags.push({'tag': u, 'product':t.name});
       })
   })


   console.log(JSON.stringify(productTags));

   /*
   [
    { "tag": "nature", "product": "Product A" }, 
    { "tag": "outdoor", "product": "Product A" }, 
    { "tag": "winter", "product": "Product A" }, 
    { "tag": "winter", "product": "Product B" }, 
    { "tag": "hiking", "product": "Product B" }, 
    { "tag": "camping", "product": "Product A" }, 
    { "tag": "camping", "product": "Product B" }, 
    { "tag": "snow", "product": "Product B" }, 
    { "tag": "vacation", "product": "Product C" }, 
    { "tag": "family", "product": "Product B" }, 
    { "tag": "family", "product": "Product C" }, 
    { "tag": "kids", "product": "Product C" }, 
    { "tag": "river", "product": "Product C" }, 
    { "tag": "lake", "product": "Product C" }, 
    { "tag": "fishing", "product": "Product C" }
] */

(Edited later) Correction:

To form the correct object, I have changed the code to:

const initialState = [
     {id:1 ,name: 'Product A', image: 'pic-001.jpg', tags: ['nature', 'camping', 'winter', 'outdoor']},
     {id:2 ,name: 'Product B', image: 'pic-002.jpg', tags: ['winter', 'hiking', 'family', 'camping', 'snow']},
     {id:3 ,name: 'Product C', image: 'pic-003.jpg', tags: ['vacation', 'family', 'kids', 'river', 'lake', 'fishing']}
   ]

   let allTags = [];
   initialState.map((t)=>t.tags).forEach((a)=>a.forEach((b)=>allTags.push(b)))
   let uniqueTags = allTags.filter((a,i,arr)=>!arr.includes(a,i+1))


   productTags = [];
   uniqueTags.forEach((u)=>{
       let productName = [];
       initialState.forEach((t)=>{
           if(t.tags.includes(u))
            productName.push(t.name);
       })
       productTags.push({tag:u, products:productName}); 
   })

   console.log(JSON.stringify(productTags));

   /*
    productTags = [
        {"tag":"nature","products":["Product A"]},
        {"tag":"outdoor","products":["Product A"]},
        {"tag":"winter","products":["Product A","Product B"]},
        {"tag":"hiking","products":["Product B"]},
        {"tag":"camping","products":["Product A","Product B"]},
        {"tag":"snow","products":["Product B"]},
        {"tag":"vacation","products":["Product C"]},
        {"tag":"family","products":["Product B","Product C"]},
        {"tag":"kids","products":["Product C"]},
        {"tag":"river","products":["Product C"]},
        {"tag":"lake","products":["Product C"]},
        {"tag":"fishing","products":["Product C"]}
    ] 
    */

Upvotes: 1

Daniel Erez
Daniel Erez

Reputation: 38

you can use indexOf function

var foo = initialState.filter(function(elm){
  return elm.tags.indexOf("camping")>=0
});

Upvotes: 1

Related Questions