Skip to content

Instantly share code, notes, and snippets.

@jherax
Last active February 23, 2024 12:59
Show Gist options
  • Save jherax/f11d669ba286f21b7a2dcff69621eb72 to your computer and use it in GitHub Desktop.
Save jherax/f11d669ba286f21b7a2dcff69621eb72 to your computer and use it in GitHub Desktop.
Filters an array of objects with multiple match-criteria.
/**
* 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);
});
});
@rakathal
Copy link

rakathal commented Aug 17, 2022

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?

@klayus
Copy link

klayus commented Sep 29, 2022

hey man! thank you a million!!! if you ever come to romania i'll buy you 10 beers!!!!!!!!!!!!!!!!!!!

@elpahlevi
Copy link

Hey dude, thanks for sharing! Your snippet is handy so I can solve my problem related to filtering data using multiple criteria

@MLS535
Copy link

MLS535 commented Jan 16, 2023

Great code!
@estherjsuh where you able to solve it? I have the same problem....

@circa10a
Copy link

I made a small lib to solve this problem
https://github.com/circa10a/filter-object-array

@AshrafulIslam2
Copy link

AshrafulIslam2 commented Feb 7, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment