Reputation: 4558
I can't seem to think about how I can overcome this issue where there might be any amount of filters as objects which will help me to filter out the data array.
data = [
{
id: 1,
first_name: 'Colver',
}, {
id: 2,
first_name: 'Brodie',
}, {
id: 3,
first_name: 'Philippa',
}, {
id: 4,
first_name: 'Taite',
}, {
id: 5,
first_name: 'Pierson'
}
];
filters = [
{
field: 'id',
operator: 'between',
value: '2-5'
},
{
field: 'first_name',
operator: 'eq',
value: 'Philippa'
}
];
ngOnInit(): void {
const filteredItems = [];
this.data.forEach(item => {
this.filters.forEach((filter, filterIndex) => {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
filteredItems.push(item);
}
break;
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
filteredItems.push(item);
}
break;
}
});
});
console.log(filteredItems);
}
I basically want the filteredItems to output like below since the id is between 2 and 5 and the first_name is Philippa. But since I'm iterating the filters 2 times both the times items gets pushed to filteredItems.
[{
id: 3,
first_name: 'Philippa',
}]
Upvotes: 0
Views: 1588
Reputation: 1437
Instead of using
const filteredItems = [];
this.data.forEach(item => {
// [...]
filteresItems.push(item)
// [...]
});
use Array's filter:
const filteredItems = this.data.filter(item => {
// [...]
let match = true; // or false
return match;
});
Taking your whole example, you could use:
function passes(item, filter) {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
return true;
}
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
return true;
}
}
return false;
}
const filteredItems = this.data.filter(
item => this.filters
.map(filter => passes(item, filter))
.every());
Upvotes: 0
Reputation: 386520
You could take Array#every
and an object for getting the right operator function.
const
data = [{ id: 1, first_name: 'Colver' }, { id: 2, first_name: 'Brodie' }, { id: 3, first_name: 'Philippa' }, { id: 4, first_name: 'Taite' }, { id: 5, first_name: 'Pierson' }],
filters = [{ field: 'id', operator: 'between', value: '2-5' }, { field: 'first_name', operator: 'eq', value: 'Philippa' }],
operators = {
between: (field, range) => {
const [min, max] = range.split('-').map(Number);
return min <= field && field <= max;
},
eq: (field, value) => field === value
},
result = data.filter(o =>
filters.every(({ field, operator, value }) =>
operators[operator](o[field], value)
)
);
console.log(result);
Upvotes: 3
Reputation: 35482
Use Array.prototype.every
to make sure every filter passes, and if so, push it to the array:
ngOnInit(): void {
const filteredItems = this.data.forEach(item =>
this.filters.every((filter, filterIndex) => {
const itemValue = item[filter.field];
switch (filter.operator) {
case 'eq':
if (itemValue === filter.value) {
return true;
}
break;
case 'between':
const [firstValue, secondValue] = filter.value.split('-');
if (itemValue > firstValue && itemValue < secondValue) {
return true;
}
break;
}
return false;
})
);
console.log(filteredItems);
}
Upvotes: 0
Reputation: 89139
You can perform a reduce
operation over the filters array and use Array#filter
to remove objects on each iteration.
const data = [
{
id: 1,
first_name: 'Colver',
}, {
id: 2,
first_name: 'Brodie',
}, {
id: 3,
first_name: 'Philippa',
}, {
id: 4,
first_name: 'Taite',
}, {
id: 5,
first_name: 'Pierson'
}
],
filters = [
{
field: 'id',
operator: 'between',
value: '2-5'
},
{
field: 'first_name',
operator: 'eq',
value: 'Philippa'
}
];
const res = filters.reduce((acc,{field,operator,value})=>
acc.filter(o => operator === 'eq' && o[field] === value ||
operator === 'between' && o[field] >= value.split('-')[0]
&& o[field] <= value.split('-')[1]), data);
console.log(res);
Upvotes: 0