I'm trying to make a filter. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.
This is how data look like:
var data = [
{id: "123", color: "Red", model: "Tesla"},
{id: "124", color: "Black", model: "Honda"},
{id: "125", color: "Red", model: "Audi"},
{id: "126", color: "Blue", model: "Tesla"}]
Filter keys are color and model. But sometimes I will filter only by color or model and sometimes by both. I want to make a function that will cover both cases. Also, a user can choose many values (Tesla, Honda...).
Key can be only color, or only model, or both. Values can look like: only "Red", "Red" and "Blue", or "Red" and "Tesla", or "Red", "Blue" and "Tesla"... Depends on what user choose.
I tried this:
var filtered = [];
data.forEach(item => {
filterByKey.forEach(key => {
values.forEach(value => {
if (item[key] === value) {
filtered.push(item);
}
});
});
});
Here is JsFiddle
My loop works well when I have one filter key, but it doesn't work well when I have more than one key. Is it a good idea to pass keys and values as an array?
No jQuery please, only pure JavaScript.
I'm trying to make a filter. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.
This is how data look like:
var data = [
{id: "123", color: "Red", model: "Tesla"},
{id: "124", color: "Black", model: "Honda"},
{id: "125", color: "Red", model: "Audi"},
{id: "126", color: "Blue", model: "Tesla"}]
Filter keys are color and model. But sometimes I will filter only by color or model and sometimes by both. I want to make a function that will cover both cases. Also, a user can choose many values (Tesla, Honda...).
Key can be only color, or only model, or both. Values can look like: only "Red", "Red" and "Blue", or "Red" and "Tesla", or "Red", "Blue" and "Tesla"... Depends on what user choose.
I tried this:
var filtered = [];
data.forEach(item => {
filterByKey.forEach(key => {
values.forEach(value => {
if (item[key] === value) {
filtered.push(item);
}
});
});
});
Here is JsFiddle
My loop works well when I have one filter key, but it doesn't work well when I have more than one key. Is it a good idea to pass keys and values as an array?
No jQuery please, only pure JavaScript.
Share Improve this question asked Jun 16, 2017 at 13:22 snoopy25snoopy25 1,3564 gold badges12 silver badges15 bronze badges8 Answers
Reset to default 12You can use filter()
with every()
and check if value of current object with current key exits in values
array using includes()
var data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Tesla"}]
var keys = ["color", 'model'];
var values = ["Tesla", "Audi", "Red"];
var result = data.filter(function(e) {
return keys.every(function(a) {
return values.includes(e[a])
})
})
console.log(result);
You could use a combined approach with a seach object which keeps the conditions, like
{ model: 'Tesla', // a single value color: ['red', 'blue'], // a some value price: { // a range/interval min: 2000, max: 3000 }, transmission: v => v.toLowerCase() === 'automatic' // a function }
var useConditions = search => a => Object.keys(search).every(k =>
a[k] === search[k] ||
Array.isArray(search[k]) && search[k].includes(a[k]) ||
typeof search[k] === 'object' && +search[k].min <= a[k] && a[k] <= +search[k].max ||
typeof search[k] === 'function' && search[k](a[k])
),
data = [{ id: "123", color: "Red", model: "Tesla" }, { id: "124", color: "Black", model: "Honda" }, { id: "125", color: "Red", model: "Audi" }, { id: "126", color: "Blue", model: "Tesla" }],
filters = { color: ['Red', 'Blue'], model: 'Tesla' };
console.log(data.filter(useConditions(filters)));
You can use Array.prototype.filter() where the function to test each element of the array is:
el => !!filterBy.toString().match(new RegExp(`(?=.*${el.color})(?=.*${el.model})`))
It consist of a regular expression new RegExp(`(?=.*${el.color})(?=.*${el.model})`))
that match to strings color
and model
in another string filterBy.toString()
var data = [{id: "123", color: "Red", model: "Tesla"}, {id: "124", color: "Black", model: "Honda"}, {id: "125", color: "Red", model: "Audi"}, {id: "126", color: "Blue", model: "Tesla"}],
filterBy = ['Tesla', 'Audi', 'Red', 'Black'],
result = data.filter(el => !!filterBy.toString().match(new RegExp(`(?=.*${el.color})(?=.*${el.model})`)));
console.log(result);
And also, you can combine Array.prototype.filter() and Array.prototype.includes():
var data = [{id: "123", color: "Red", model: "Tesla"}, {id: "124", color: "Black", model: "Honda"}, {id: "125", color: "Red", model: "Audi"}, {id: "126", color: "Blue", model: "Tesla"}],
filterBy = ['Tesla', 'Audi', 'Red', 'Black'],
result = data.filter(el => filterBy.includes(el.model) && filterBy.includes(el.color));
console.log(result);
For a case like this here's what I just do:
function _filter(data, query) { // query = "Red" or "Tesla"
return data.filter(el => {
return el.model.toLowerCase().indexOf(query.toLowerCase()) !== -1 ||
el.name.toLowerCase().indexOf(query.toLowerCase()) !== -1;
});
}
Now this function searches data on the model key and name key.
Using filter()
to filter data, combined with some()
to check if multiple keys
match at least one of the strings from the values
using includes()
// array --------------------
const data = [
{ id: '123', color: 'Red', model: 'Tesla' },
{ id: '124', color: 'Black', model: 'Honda' },
{ id: '125', color: 'Red', model: 'Audi' },
{ id: '126', color: 'Blue', model: 'Tesla' },
];
// filter exact match --------------------
const keysExact = ['color', 'model'];
const valuesExact = ['Tesla', 'Audi', 'Red'];
const resultExact = data.filter((item) =>
keysExact.every((a) => valuesExact.includes(item[a]))
);
console.log(resultExact);
// result:
// [
// { id: '123', color: 'Red', model: 'Tesla' },
// { id: '125', color: 'Red', model: 'Audi' },
// ];
Using filter()
to filter data, combined with some()
to check if multiple keys
contain at least one of the strings from the values
using includes()
.
// array --------------------
const data = [
{ id: '123', color: 'Red', model: 'Tesla' },
{ id: '124', color: 'Black', model: 'Honda' },
{ id: '125', color: 'Red', model: 'Audi' },
{ id: '126', color: 'Blue', model: 'Tesla' },
];
// filter data by keys containing values string (at least one of the string in values) --------------------
const keysSome = ['color', 'model'];
const valuesSome = ['Tes', 're'];
const resultSome = data.filter((item) =>
keysSome.some((key) =>
valuesSome.some((val) => item[key].toLowerCase().includes(val.toLowerCase()))
)
);
console.log(resultSome);
// result:
// [
// { id: '123', color: 'Red', model: 'Tesla' },
// { id: '125', color: 'Red', model: 'Audi' },
// { id: '126', color: 'Blue', model: 'Tesla' },
// ];
Using filter()
to filter data, combined with every()
to check if multiple keys
contain all strings from the values
using includes()
.
// array --------------------
const data = [
{ id: '123', color: 'Red', model: 'Tesla' },
{ id: '124', color: 'Black', model: 'Honda' },
{ id: '125', color: 'Red', model: 'Audi' },
{ id: '126', color: 'Blue', model: 'Tesla' },
];
// filter data by keys containing values string (matches all strings from values) --------------------
const keysEvery = ['color', 'model'];
const valuesEvery = ['Tes', 're'];
const resultEvery = data.filter((item) =>
keysEvery.every((key) =>
valuesEvery.some((val) => item[key].toLowerCase().includes(val.toLowerCase()))
)
);
console.log(resultEvery);
// result:
// [
// { id: '123', color: 'Red', model: 'Tesla' }
// ]
Is this what you want to achieve?
var data = [
{id: "123", color: "Red", model: "Tesla"},
{id: "124", color: "Black", model: "Honda"},
{id: "125", color: "Red", model: "Audi"},
{id: "126", color: "Blue", model: "Tesla"}
];
var allowedColors = ["Red", "Blue"];
var allowedModels = ["Tesla", "Audi"];
function filter (cars, colors, models) {
return cars.filter(function (car) {
return colors.indexOf(car.color) !== -1 && // check if the car's color is allowed
models.indexOf(car.model) !== -1; // check if the car's model is allowed
});
}
var filtered = filter(data, allowedColors, allowedModels);
console.log(filtered);
Filtering is native in JS, try this:
data.filter(item => item.color==='Red');
// or in the old fashion
data.filter(function(item){ return item.color==='Red';} );
Here, I have a different scenario.
I have an object
d={r1: {name: "r1", validation: true}, r2: {name: "r2", validation: true}};
and another array
a = ["r1"];
Here, the result I want is
d={r1: {name: "r1", validation: true}}