Home > Software design >  Apply a filter with multiple values in javascript object
Apply a filter with multiple values in javascript object

Time:08-03

I am working on a filter with javascript. I have a json object of all data and filters in json as well. I need to apply that filter with between for example filter all the data which has price between 50-100.

Sample data is like this

var filterEvents = [
    {id:1,price:25},
    {id:2,price:45},
    {id:3,price:57},
    {id:4,price:80},
    {id:5,price:105},
    {id:6,price:200}
    ];

Filters json looks like this

var budgets =["1","2","3","4","5"]; // 1 for <30 , 2 for 31-50, 3 for 51-100, 4 for 101-150, 5 for 151 

Filter json can have any number of data

I am trying it with this if else condition.

var filterEvents = [
{id:1,price:25},
{id:2,price:45},
{id:3,price:57},
{id:4,price:80},
{id:5,price:105},
{id:6,price:200}
];

//var budgets =["1","2","3","4","5"]; // 1 for <30 , 2 for 31-50, 3 for 51-100, 4 for 101-150, 5 for 151 
var budgets =["1","2","3"];
//var budgets =["1","2"];
//var budgets =["1"];
if(budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 30  ;
                                  });
}
else if(budgets.includes('1') && budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 50   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 100   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <= 150   ;
                                  });
}

else if(budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    
}

if(!budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& !budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >150  ;
                                  });
}

if(!budgets.includes('1') && !budgets.includes('2')&& !budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >100  ;
                                  });
}

if(!budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >50  ;
                                  });
}

if(!budgets.includes('1') && budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price >30  ;
                                  });
}

if(budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& !budgets.includes('4') && !budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <=30 || element.price >50 && element.price<100 ;
                                  });
}

if(budgets.includes('1') && !budgets.includes('2')&& budgets.includes('3')&& budgets.includes('4') && budgets.includes('5'))
{
    filterEvents = filterEvents.filter(element => {
                             return element.price <=30 || element.price >50 ;
                                  });
}

console.log(filterEvents);

Here is the working JSfiddle

The issue in this code is a will need to add all the conditions and it could stop working for some data. I am finding a more accurate solution.

CodePudding user response:

You can use the Array.prototype.filter() Method to remove any non-matching elements.

Although it is neccessary for more automation, that you have some definition of your Budget-Values as you have written as a comment in your source code. Like a table or an array storing the conditions for each value.

const budgetCondition = {
  '1': (value) => value <= 30,
  '2': (value) => value >= 31 && value <= 50,
  '3': (value) => value >= 51 && value <= 100,
  '4': (value) => value >= 101 && value <= 150,
  '5': (value) => value >= 151
};

This is an Object with indexes matching your Values in your budgets-Array. As Values i've use Arrow-Functions (normal function(value){ Boolean operation ...} would be sufficient too) stored where we would provide the comparing budgetValue against and retrieve the Boolean value if this value should be kept or be removed.

Then you could iterate through all set Budget-Filters and grab the necessary filterCondition from the budgetCondition-Object.

let filteredData = filterEvents.filter(item => {
  let filtered = !!budgets.find(filterIndex => {
    if (budgetCondition[filterIndex](item.price)) return true;
    return false;
  });
  return filtered;
});

With filterEvents.filter() we iterate through all Items of the array and remove any Elements, which returns false in the Callback function. To determine which elements we want to keep and returning true, we use the Array.prototype.find() Method.
This then iterates through all filterIndexes set and checks if the current element should be kept.
To achieve this, we use the previously defined filterCondition Object by accessing the corresponding condition-Function with the filterIndex.

We then provide the Price-value and will get a boolean value if this price matches the condition.
If it matches we keep this element and return a true for the filter-Method.


Down below i've added a snippet demonstrating the complete procedure.
Keep in mind, that if you want to add further conditions, you have to include those with an Index in the conditions object with a function, which will return a boolean value if the condition is met.

var filterEvents = [{
    id: 1,
    price: 25
  },
  {
    id: 2,
    price: 45
  },
  {
    id: 3,
    price: 57
  },
  {
    id: 4,
    price: 80
  },
  {
    id: 5,
    price: 105
  },
  {
    id: 6,
    price: 200
  }
];

var budgets = ["3", "4", "5"];



function filterData(data, budgets) {
  // We define an Object like structure for our definitions, how to filter
  // We match the index to our values in the budgets-Array and associate a function
  // which will resolve into a boolean value if the condition well be met.
  const budgetCondition = {
    '1': (value) => value <= 30,
    '2': (value) => value >= 31 && value <= 50,
    '3': (value) => value >= 51 && value <= 100,
    '4': (value) => value >= 101 && value <= 150,
    '5': (value) => value >= 151
  };

  // We then want to filter out all elements, that doesn't fit any set filters.
  return filterEvents.filter(item => {

    // We check if the current checking element will met any filters set in our budgets-Array
    // This Method would return the first matching filterIndex, that resolves to a true condition
    // but with the doulbe Exclamation mark we convert this result into a boolean value.
    let filtered = !!budgets.find(filterIndex => {

      // We check each FilterIndex thats set in the budgets-Array and access the corresponding       // condition function in our budgetCondition-Object.
      // If the Function resolved to true, we return the fulfilling filterIndex, therefore  
      // signaling, that the Element matches a filter and should be kept.
      // 
      // As a Comment pointed out, we have to check if the filterIndex matches any filter in 
      // our condition Object. If not, we ignore the check
      if (budgetCondition[filterIndex] && budgetCondition[filterIndex](item.price)) return true;

      // If it didnt resolve the function to true, we return false, therefore signaling that this 
      // filterCondition wasnt met and are looking further.
      return false;
    });

    // If we have found a matching filter this will return true. If we have iterated through all 
    // set budgetFilters and none of them resolved to true, we will return a false and therefore 
    // filter out this element.
    return filtered;
  });
}

console.log("First Filter: ",filterData(filterEvents, ["1", "2", "3"]));
console.log("First Filter: ",filterData(filterEvents, ["3", "4", "6"]));

CodePudding user response:

var filterEvents = [
{id:1,price:25},
{id:2,price:45},
{id:3,price:57},
{id:4,price:80},
{id:5,price:105},
{id:6,price:200}
];

//var budgets =["1","2","3","4","5"]; // 1 for <30 , 2 for 31-50, 3 for 51-100, 4 for 101-150, 5 for 151 
var budgets =["3","4","5"];
//var budgets =["1","2"];
//var budgets =["1"];

var rules={
    "1":{"gt":0,"lt":30},
    "2":{"gt":31,"lt":50},
    "3":{"gt":51,"lt":100},
    "4":{"gt":101,"lt":150},
    "5":{"gt":151,"lt":"max"}
}

var gtRules = budgets.map(x=>rules[x]["gt"]);
var ltRules = budgets.map(x=>rules[x]["lt"]);


var bFrom = 0;
var bTo = 0;

bFrom = Math.min(...gtRules);
if(!ltRules.includes("max")){
    bTo = Math.max(...ltRules);
}


filterEvents = filterEvents.filter(element => {
        if(bTo>0){
        return element.price >= bFrom && element.price <= bTo;
    }else{
        return element.price >= bFrom;
    }                         
});

console.log(filterEvents);

CodePudding user response:

In order to make it easier and more understandable, I will use the same conditions and sources that you provided, just adding the remaining solution that you request.

// This is your original json object exactly as you provided:
var filterEvents = [
 { id: 1, price: 25 },
 { id: 2, price: 45 },
 { id: 3, price: 57 },
 { id: 4, price: 80 },
 { id: 5, price: 105 },
 { id: 6, price: 200 }
];

// This is your budgets array filter. Here I just reduced the extension by excluding some values to simulate how the result will change according you change the values in this array.
var budgets = ["1", "2", "3"];

// Now, let's declare all the possible status in which we can receive your filter. 
var filterOne = ["1"];
var filterTwo = ["1", "2"];
var filterThree = ["1", "2", "3"];
var filterFour = ["1", "2", "3", "4"];
var filterFive = ["1", "2", "3", "4", "5"];

// Now, let's declare all the possible results based on the filter received.
var isFilterOneTrue = filterOne.every(el => budgets.includes(el))
var isFilterTwoTrue = filterTwo.every(el => budgets.includes(el))
var isFilterThreeTrue = filterThree.every(el => budgets.includes(el))
var isFilterFourTrue = filterFour.every(el => budgets.includes(el))
var isFilterFiveTrue = filterFive.every(el => budgets.includes(el))

// Now we create a function to process the data above.
// Notice that here we assert each filter in descending order returning the first true, since greater filters includes the smaller ones. otherwise we will get undesired result. 

function setFilterEvents() {
 if (isFilterFiveTrue)
    return filterEvents = filterEvents.filter(element => element.price > 150);

 if (isFilterFourTrue)
    return filterEvents = filterEvents.filter(element => element.price <= 150);

 if (isFilterThreeTrue)
    return filterEvents = filterEvents.filter(element => element.price <= 100);

 if (isFilterTwoTrue)
    return filterEvents = filterEvents.filter(element => element.price <= 50);

 if (isFilterOneTrue)
    return filterEvents = filterEvents.filter(element => element.price <= 30);
 // In case none of your assertion above are met, you can return an error message. Or simply add more cases by following the logic above.
  else return { error: 'no match found' }
}

// We update the filterEvents based on our function above.
filterEvents = setFilterEvents()

// Printing the result.
// Note: Remember to change the budgets array variable according the scenario that you want to verify or the result that you want to have.
console.log(filterEvents)
  • Related