12

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?

2
  • I don't think there is any other way of doing it. You will have to iterate through the array for your condition of matching with tags. Commented Jul 6, 2017 at 13:07
  • 3
    you could just use array.indexOf in your filter function. Commented Jul 6, 2017 at 13:10

4 Answers 4

16

Like that?

const filter = 'nature';
const filteredResult = initialState.filter((item) => {
    return (item.tags.indexOf(filter) >= 0);
});
Sign up to request clarification or add additional context in comments.

5 Comments

Why not use includes?
@destoryer what's includes? It may be a feature from lodash or underscore, but I think it's not native JS.
includes not supported by IE though.
That's nice to know about, I thought it was from an utility lib! Nice :)
some how i had to convert to string for it to work. Otherwise it was buggy, not sure why. return (item.tags.toString().indexOf(tag) >= 0);. Thanks guys, and sorry for the late reply!
9

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);

1 Comment

Just what I needed
1

you can use indexOf function

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

Comments

1

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"]}
    ] 
    */

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.