-
-
Save CarlosHdz7/92f34fcc1176439dabf710feba5f20d8 to your computer and use it in GitHub Desktop.
Filters an array of objects with multiple match-criteria.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Filters an array of objects using custom predicates. | |
* | |
* @param {Array} array: the array to filter | |
* @param {Object} filters: an object with the filter criteria | |
* @return {Array} | |
*/ | |
function filterArray(array, filters) { | |
const filterKeys = Object.keys(filters); | |
return array.filter(item => { | |
// validates all filter criteria | |
return filterKeys.every(key => { | |
// ignores non-function predicates | |
if (typeof filters[key] !== 'function') return true; | |
return filters[key](item[key]); | |
}); | |
}); | |
} | |
/** | |
* The method `filterArray()` has the following signature: | |
* | |
* `function filterArray<TInput = any>(array: TInput[], filters: IFilters) => TInput[]` | |
* | |
* Where the function receives an array as the first argument, and a plain object | |
* describing the fields to filter as the last argument. | |
* The function returns an array of the same type as the input array. | |
* | |
* The signature of the filters arguments is the following: | |
* | |
* `interface IFilters { | |
* [key: string]: (value: any) => boolean; | |
* }` | |
* | |
* Where the `filters` argument is an object that contains a `key: string` | |
* and its value is a function with the value of the property to evaluate. | |
* As the function predicate is evaluated using the `Array.prototype.every()` method, | |
* then it must return a boolean value, which will determine if the item | |
* must be included or not in the filtered array. | |
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('Testing filterArray()', () => { | |
it('should filter an array of objects by custom predicates', () => { | |
const products = [ | |
{ name: 'A', color: 'Blue', size: 50, locations: ['USA', 'Europe'], details: { length: 20, width: 70 } }, | |
{ name: 'B', color: 'Blue', size: 60, locations: [], details: { length: 20, width: 70 } }, | |
{ name: 'C', color: 'Black', size: 70, locations: ['Japan'], details: { length: 20, width: 71 } }, | |
{ name: 'D', color: 'Green', size: 50, locations: ['USA'], details: { length: 20, width: 71 } }, | |
]; | |
const filters = { | |
size: size => size === 50 || size === 70, | |
color: color => ['blue', 'black'].includes(color.toLowerCase()), | |
locations: locations => locations.find(x => ['JAPAN', 'USA'].includes(x.toUpperCase())), | |
details: details => details.length < 30 && details.width >= 70, | |
}; | |
const filters = { | |
size: (size) => size === 50 || size === 70, | |
color: (color) => ['blue', 'black'].includes(color.toLowerCase()), | |
details: (details) => details.length < 30 && details.width >= 70, | |
locations: (locations) => { | |
if (locations.includes('USA')) return true; // case sensitive | |
if (locations.includes('Japan')) return true; // case sensitive | |
const url = window.location.pathname.toLowerCase(); | |
if (url.includes('/en-us/')) return true; // not case sensitive | |
if (url.includes('/es/')) return true; // not case sensitive | |
return false; | |
} | |
}; | |
const filtered = filterArray(products, filters); | |
const expected = [ | |
{ name: 'A', color: 'Blue', size: 50, locations: ['USA', 'Europe'], details: { length: 20, width: 70 } }, | |
{ name: 'C', color: 'Black', size: 70, locations: ['Japan'], details: { length: 20, width: 71 } }, | |
]; | |
expect(filtered).toStrictEqual(expected); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ignores case-sensitive | |
const getValue = value => (typeof value === 'string' ? value.toUpperCase() : value); | |
/** | |
* Filters an array of objects (one level-depth) with multiple criteria. | |
* | |
* @param {Array} array: the array to filter | |
* @param {Object} filters: an object with the filter criteria | |
* @return {Array} | |
*/ | |
function filterPlainArray(array, filters) { | |
const filterKeys = Object.keys(filters); | |
return array.filter(item => { | |
// validates all filter criteria | |
return filterKeys.every(key => { | |
// ignores an empty filter | |
if (!filters[key].length) return true; | |
return filters[key].find(filter => getValue(filter) === getValue(item[key])); | |
}); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('Testing filterPlainArray()', () => { | |
it('should filter an array of objects with one level-depth', () => { | |
const products = [ | |
{ name: 'A', color: 'Blue', size: 50 }, | |
{ name: 'B', color: 'Blue', size: 60 }, | |
{ name: 'C', color: 'Black', size: 70 }, | |
{ name: 'D', color: 'Green', size: 50 }, | |
]; | |
const filters = { | |
color: ['BLUE', 'black'], | |
size: [70, 50], | |
}; | |
const filtered = filterPlainArray(products, filters); | |
const expected = [ | |
{ name: 'A', color: 'Blue', size: 50 }, | |
{ name: 'C', color: 'Black', size: 70 }, | |
]; | |
expect(filtered).toStrictEqual(expected); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment