'How to filter object with multiple optionnal conditions?

I have this array of objects:

[
 {name: "John", surname: "Doe", car: "BWM"}, 
 {name: "Louis", surname: "Vuitton", car: "MERCEDES"}, 
 {name: "Bob", surname: "Ross", car: "FORD"}, 
 {name: "Dylan", surname: "James", car: "FERRARI"},
 {name: "Damien", surname: "Rivers", car: "JAGUAR"},
]

And I have this code

return this._object.filter(object => object.car === params1 && object.car === params2  && object.car=== params3)

params can be what ever brand car, but they are optional besides params1, user can provide only params1 and let the other two undefined.

Params are selected by the user on a select html option, he can choose up to 3 car brand, so 3 params and i pass it as url parameters and pass these parameters to my function

I want to do something like in one line : if params2 and params3 exists don't change the code snippet, if they don't exist, only do the filter on params1

Example 1: if params1 = BMW and params 2-3 = undefined it would return this object {name: "John", surname: "Doe", car: "BWM"}

Example 2: if params1 = BMW, params2 = MERCEDES it would return this result :

{name: "John", surname: "Doe", car: "BWM"}
{name: "Louis", surname: "Vuitton", car: "MERCEDES"},`

Same concept with params 3 == FERRARI

I can't see how I can do that with few lines/one line, besides doing if statement everywhere

Thanks !



Solution 1:[1]

you can do something like this

const filterData = (data, ...params) => data.filter(d => params.includes(d.car))



const data = [{name: "John", surname: "Doe", car: "BMW"}, 
 {name: "Louis", surname: "Vuitton", car: "MERCEDES"}, 
 {name: "Bob", surname: "Ross", car: "FORD"}, 
 {name: "Dylan", surname: "James", car: "FERRARI"},
 {name: "Damien", surname: "Rivers", car: "JAGUAR"},]
 
 
 console.log(filterData(data, 'BMW'))
 console.log(filterData(data, 'BMW', 'MERCEDES'))
 

Solution 2:[2]

You can make the code even more flexible. Instead of passing 3 different params, pass an array like below.

let cars = ["BMW", "MERCEDES"];

now you can check it using javascript's includes method.

return this._object.filter(object => cars.includes(object.car))

Solution 3:[3]

By using Array.prototype.includes() you can check against a number of target expressions. It will return true if the argument is equal to at least one element of the array.

In an initial args.map() loop I make sure that the input values are all upper case.

const data=[{name: "John", surname: "Doe", car: "BMW"}, 
 {name: "Louis", surname: "Vuitton", car: "MERCEDES"}, 
 {name: "Bob", surname: "Ross", car: "FORD"}, 
 {name: "Dylan", surname: "James", car: "FERRARI"},
 {name: "Damien", surname: "Rivers", car: "JAGUAR"}];

function filt(...args){
 args=args.map(a=>a.toUpperCase());
 return data.filter(d=>
  args.includes(d.car))
}

console.log(filt("BMW","Mercedes"));
console.log(filt("jaguar"))

Solution 4:[4]

First param is an array of objects, second, third, and so on is a rest operator that will accept zero or more values. Once passed into the function it will be an array:

const findValues = (objArray, ...vals) => //...

Next .flatMap() iterates over the object array. On each object, Object.entries() converts it into an array of pairs:

objArray.flatMap(obj => Object.entries(obj) //...
/* {name: "John", surname: "Doe", car: "BWM"} converted into 
   [["name", "John"], ["surname", "Doe"], ["car", "BWM"]] */

Each array of pairs is then taken by .flatMap() and on each iteration it each of it's values will be compared to the vals array (second parameter with rest operator). Note that the vals array was converted to lowercase by .map() as well as each value of the array of pairs because .includes() is case sensitive. The comparison is a ternary .includes() returns true then the object (not the array of pairs) is returned and if false, an empty array is returned (.flatMap() returns an array then flattens it by one level, so returning an empty array is essentially returning nothing).

.flatMap(([key,val]) => 
[...vals].map(val => val.toLowerCase())
.includes(val.toLowerCase()) ? obj : []));

This function will accept any number of values to search, and it's case-insensitive.

const data=[{name:"John",surname:"Doe",car:"BWM"},{name:"Louis",surname:"Vuitton",car:"MERCEDES"},{name:"Bob",surname:"Ross",car:"FORD"},{name:"Dylan",surname:"James",car:"FERRARI"},{name:"Damien",surname:"Rivers",car:"JAGUAR"}];

const findValues = (objArray, ...vals) => objArray.flatMap(obj => Object.entries(obj).flatMap(([key, val]) => [...vals].map(val => val.toLowerCase()).includes(val.toLowerCase()) ? obj : []));

console.log(findValues(data, "JAgUAR", "Dylan"));
console.log('==================');
console.log(findValues(data, "ford", "Dylan", "vuitton", "rivers"));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 R4ncid
Solution 2 Daljit Kumar
Solution 3
Solution 4