-
-
Save jherax/f11d669ba286f21b7a2dcff69621eb72 to your computer and use it in GitHub Desktop.
/** | |
* 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. | |
*/ |
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); | |
}); | |
}); |
// 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])); | |
}); | |
}); | |
} |
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); | |
}); | |
}); |
(() => {
const hotels = [
{"id":1, "name": "4 Seasons", "price":120.70, "currency":"USD", "country":"Canada"},
{"id":2, "name": "Triton palm", "price":112, "currency":"USD", "country": "Canada"},
{"id":3, "name": "Herrington place", "price":180, "currency":"USD", "country": "Poland"}
];
const keep_these_hotels = {
country: ['Canada'],
price: { min: 100, max: 150 }
};
const filter_function = (hotels) => {
return hotels.filter((hotel) => {
return Object.keys(keep_these_hotels).some((key) => {
if (key === 'country'){
return keep_these_hotels.country.some((country) => country === hotel.country);
}
if (key === 'price'){
return hotel.price >= keep_these_hotels.price.min && hotel.price <= keep_these_hotels.price.max;
}
});
})
}
console.log(filter_function(hotels));
})();
// The keep_these_hotels doesnt require for all conditions to be met, just one of them. Since you didn't mention that part I'm assumed it this way.
hello
thank you guys,
i have a small problem with this function
filterPlainArray(array, filters) { const filterKeys = Object.keys(filters); return array.filter(item => { // validates all filter criteria return filterKeys.some(key => { // ignores an empty filter if (!filters[key].length) return true; return filters[key](filter => filter === item[key]); }); }); }
when i set filters like this
var filterData = { typeTraitement:[0], typeExecution:[0], };
and
var dataArray =[ {"typeTraitement":0, "typeExecution": 1} {"typeTraitement":1, "typeExecution": 0} {"typeTraitement":2, "typeExecution": 0} }]
the result is null and is happing only win i filter with 0 the others values is correct
some one has any idea why this happing
thank you for help
Is it too hard to ask to give us a working example?
return filters[key](filter => filter === item[key]); }); }); }
is not even valid syntax.
Is it too hard to ask to give us a working example?
return filters[key](filter => filter === item[key]); }); }); }
is not even valid syntax.
thank you pro
I'm using TypeScript
here the syntax of function
filterPlainArray(array, filters){
const filterKeys = Object.keys(filters);
return array.filter(item => {
return filterKeys.some(key => {
if (!filters[key].length) return true;
return filters[key].find(filter => filter === item[key]);
});
});
}
filtres data is
filtres
var filters = { typeTraitement:[0], typeExecution:[0], };
and
dataArray
var dataArray =[ {"typeTraitement":0, "typeExecution": 1},
{"typeTraitement":1, "typeExecution": 0} ,
{"typeTraitement":2, "typeExecution": 0},
{"typeTraitement":2, "typeExecution": 3} }];
result -result is empty-
var result=this.filterPlainArray(dataArray ,filters );
expected result is
[ {"typeTraitement":0, "typeExecution": 1},
{"typeTraitement":1, "typeExecution": 0} ,
{"typeTraitement":2, "typeExecution": 0} }]
remark
the function work fine with any number in filters other than 0
Question: What if the Value are multiple that is delimited by semicolon ";",
Sample Data :
Title multi value = "Station 1;Station 2"
Filter State = Station 1 //This is the user selected in a multi checkbox option
const filterKeys = Object.keys(filters);
return arr.filter(eachObj => {
return filterKeys.every(eachKey => {
if (!filters[eachKey].length) {
return true; // passing an empty filter means that filter is ignored.
}
**return filters[eachKey].includes(eachObj[eachKey]);**
// The current behaviour, it only retrieves the exact data sample is "Station 1"= "Station 1"
});
});
};
@jherax -Great, thanks for this brainstorming thread.
I am struggling with nested keys in json to compare dynamically.
my data
{
"id": 1,
"user_status": "ACTIVE",
"roles": [{"id": "APP_ADMIN", "name": "App Admin"}, {"APP_USER": , "name": "App User"}],
"permissions": {"apps": ["abc", "pqr"]}
},
I am currently filtering it by user_status
because it is straightforward, but need your help to make dynamic condition for roles
and apps
which is inside permission
. How i can create condition for apps and roles.
@jherax - I can't ever shake your hand - but please accept this thank you so much
for sharing this !
Cheers to writing better code with fewer headaches !
Consider I have the below data:
[
{
apId: "c3:89:6f:1a:83:5e",
description: "Kiruna Ramp Beacon",
estimated: false,
externalId: null,
id: 718311,
name: "BLE_1",
posX: 6622.404970932526,
posY: 2834.686893101607,
posZ: 3012.490824884788,
timestamp: 0,
type: "BLE_BEACON"
},
{
apId: "e4:97:29:25:41:73",
description: "Kiruna Ramp Beacon",
estimated: false,
externalId: null,
id: 718312,
name: "BLE_2",
posX: 6401.213050968167,
posY: 2791.9930699182455,
posZ: 2983.5542385630656,
timestamp: 0,
type: "BLE_BEACON"
},
{
apId: "ce:76:58:8c:66:e1",
description: "Kiruna Ramp Beacon",
estimated: false,
externalId: null,
id: 718313,
name: "BLE_3",
posX: 6175.356128422606,
posY: 2863.5582614152468,
posZ: 2956.701987555463,
timestamp: 0,
type: "BLE_BEACON"
}
]
Expected output is:
[
{
apId: "c3:89:6f:1a:83:5e",
description: "Kiruna Ramp Beacon",
name: "BLE_1",
posX: 6622.404970932526,
posY: 2834.686893101607,
posZ: 3012.490824884788,
type: "BLE_BEACON",
},
{
apId: "e4:97:29:25:41:73",
description: "Kiruna Ramp Beacon",
name: "BLE_2",
posX: 6401.213050968167,
posY: 2791.9930699182455,
posZ: 2983.5542385630656,
type: "BLE_BEACON",
},
{
apId: "ce:76:58:8c:66:e1",
description: "Kiruna Ramp Beacon",
name: "BLE_3",
posX: 6175.356128422606,
posY: 2863.5582614152468,
posZ: 2956.701987555463,
type: "BLE_BEACON"
}
]
How to do it in TypeScript?
hey man! thank you a million!!! if you ever come to romania i'll buy you 10 beers!!!!!!!!!!!!!!!!!!!
Hey dude, thanks for sharing! Your snippet is handy so I can solve my problem related to filtering data using multiple criteria
Great code!
@estherjsuh where you able to solve it? I have the same problem....
I made a small lib to solve this problem
https://github.com/circa10a/filter-object-array
I have an array of Sizes which is Size = ["40","XL","43","M"]
This is what my Products JSON File looks like :
[{
"productCatgoris": "womensfashion",
"productSubCatgoris": "Kamiz",
"productStoreName": "S-trade Store",
"productId": "27",
"productName": "Cotton Unstitched Salwar Kameez for Women - Pink",
"productImage": "https://images.pexels.com/photos/15388429/pexels-photo-15388429.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"productPrice": "699",
"productDiscount": "10",
"offerStatus": false,
"productBrand": "Strade",
"ExpressDelivary": true,
"FreeDelivary": true,
"productStock": "60",
"productSold": "10",
"offerStartAndEnDate": "12-12-2021-01-04-2022",
"offerName": "",
"productDescription": ["Cotton Unstitched Salwar Kameez for Women - Pink"],
"productSpecipication": {
"Brand": "S-trade",
"size": ["XL", "M", "L", "S", "2XL"],
"gender": "Womens",
"Color": ["Pink"]
},
"productShipping": "Dhaka city !!!! Feel free to buy from this site as we promise you same day delivery of any purchased items. Sookh helps you to purchase any goods or service with a very few steps. If you ever find any obligation of returning any purchased item or items, please review our Return & Refund Policy.",
"productReviews": []
},
{
"productCatgoris": "womensfashion",
"productSubCatgoris": "Kamiz",
"productStoreName": "S-trade Store",
"productId": "28",
"productName": "Cotton Unstitched Salwar Kameez for Women - Pink",
"productImage": "https://images.pexels.com/photos/15388429/pexels-photo-15388429.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"productPrice": "699",
"productDiscount": "10",
"offerStatus": false,
"productBrand": "Strade",
"ExpressDelivary": false,
"FreeDelivary": false,
"productStock": "60",
"productSold": "10",
"offerStartAndEnDate": "12-12-2021-01-04-2022",
"offerName": "",
"productDescription": ["Cotton Unstitched Salwar Kameez for Women - Pink"],
"productSpecipication": {
"Brand": "S-trade",
"size": ["41", "42", "43", "45"],
"gender": "Womens",
"Color": ["Pink"]
},
"productShipping": "Dhaka city !!!! Feel free to buy from this site as we promise you same day delivery of any purchased items. Sookh helps you to purchase any goods or service with a very few steps. If you ever find any obligation of returning any purchased item or items, please review our Return & Refund Policy.",
"productReviews": []
},
{
"productCatgoris": "womensfashion",
"productSubCatgoris": "Kaftan",
"productStoreName": "S-trade Store",
"productId": "29",
"productName": "Georgette Luxury Kaftan",
"productImage": "https://images.pexels.com/photos/15388429/pexels-photo-15388429.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"productPrice": "699",
"productDiscount": "10",
"offerStatus": false,
"productBrand": "Strade",
"ExpressDelivary": true,
"FreeDelivary": true,
"productStock": "60",
"productSold": "10",
"offerStartAndEnDate": "12-12-2021-01-04-2022",
"offerName": "",
"productDescription": ["Georgette Luxury Kaftan"],
"productSpecipication": {
"Brand": "S-trade",
"size": ["41", "42", "43", "45"],
"gender": "Womens",
"Color": ["Pink"]
},
"productShipping": "Dhaka city !!!! Feel free to buy from this site as we promise you same day delivery of any purchased items. Sookh helps you to purchase any goods or service with a very few steps. If you ever find any obligation of returning any purchased item or items, please review our Return & Refund Policy.",
"productReviews": []
},
{
"productCatgoris": "womensfashion",
"productSubCatgoris": "Kaftan",
"productStoreName": "S-trade Store",
"productId": "30",
"productName": "Georgette Luxury Kaftan",
"productImage": "https://images.pexels.com/photos/15388429/pexels-photo-15388429.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"productPrice": "699",
"productDiscount": "10",
"offerStatus": false,
"productBrand": "Strade",
"ExpressDelivary": false,
"FreeDelivary": false,
"productStock": "60",
"productSold": "10",
"offerStartAndEnDate": "12-12-2021-01-04-2022",
"offerName": "",
"productDescription": ["Georgette Luxury Kaftan"],
"productSpecipication": {
"Brand": "S-trade",
"size": ["41", "42", "43", "45"],
"gender": "Womens",
"Color": ["Pink"]
},
"productShipping": "Dhaka city !!!! Feel free to buy from this site as we promise you same day delivery of any purchased items. Sookh helps you to purchase any goods or service with a very few steps. If you ever find any obligation of returning any purchased item or items, please review our Return & Refund Policy.",
"productReviews": []
},
{
"productCatgoris": "womensfashion",
"productSubCatgoris": "Kamiz",
"productStoreName": "S-trade Store",
"productId": "31",
"productName": "Cotton Unstitched Salwar Kameez for Women - Pink",
"productImage": "https://images.pexels.com/photos/15388429/pexels-photo-15388429.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"productPrice": "699",
"productDiscount": "10",
"offerStatus": false,
"productBrand": "Strade",
"ExpressDelivary": false,
"FreeDelivary": false,
"productStock": "60",
"productSold": "10",
"offerStartAndEnDate": "12-12-2021-01-04-2022",
"offerName": "",
"productDescription": ["Cotton Unstitched Salwar Kameez for Women - Pink"],
"productSpecipication": {
"Brand": "S-trade",
"size": ["40", "41", "42", "43", "45"],
"gender": "Womens",
"Color": ["Pink"]
},
"productShipping": "Dhaka city !!!! Feel free to buy from this site as we promise you same day delivery of any purchased items. Sookh helps you to purchase any goods or service with a very few steps. If you ever find any obligation of returning any purchased item or items, please review our Return & Refund Policy.",
"productReviews": []
},
]
I have to find all products based on a given size array. That size needs to match the productSpecipication > Size[]
array. if matched, it will return the particular products as a products array.
Hello guys! Thank God I found this thread! You are saving lives!
By the way, when applying the filter, I run into the following problem: I have the price list (json file) where the prices are stored. When filtering by price, the filter ignores floating numbers. Could you tell please how to fix it?
So my json looks like this:
I tried to modify the filter like that:
But it led me to nowhere :(
Full code I have: