Skip to content

Instantly share code, notes, and snippets.

@sylvamadu
Forked from jherax/arrayFilterFactory.1.ts
Created April 4, 2022 10:26
Show Gist options
  • Save sylvamadu/0d74e37c45d8fa8dde9f8abfa0aec86c to your computer and use it in GitHub Desktop.
Save sylvamadu/0d74e37c45d8fa8dde9f8abfa0aec86c to your computer and use it in GitHub Desktop.

Revisions

  1. @jherax jherax revised this gist Mar 9, 2020. 2 changed files with 39 additions and 2 deletions.
    26 changes: 24 additions & 2 deletions filterArray.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    /**
    * Filters an array of objects by custom predicates.
    * Filters an array of objects using custom predicates.
    *
    * @param {Array} array: the array to filter
    * @param {Object} filters: an object with the filter criteria
    @@ -15,4 +15,26 @@ function filterArray(array, filters) {
    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.
    */
    15 changes: 15 additions & 0 deletions filterArray.test.js
    Original file line number Diff line number Diff line change
    @@ -13,6 +13,21 @@ describe('Testing filterArray()', () => {
    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 = [
  2. @jherax jherax revised this gist Jul 30, 2019. 6 changed files with 85 additions and 45 deletions.
    18 changes: 18 additions & 0 deletions filterArray.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    /**
    * Filters an array of objects by 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]);
    });
    });
    }
    24 changes: 24 additions & 0 deletions filterArray.test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,24 @@
    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 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);
    });
    });
    21 changes: 21 additions & 0 deletions filterPlainArray.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,21 @@
    // 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]));
    });
    });
    }
    22 changes: 22 additions & 0 deletions filterPlainArray.test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    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);
    });
    });
    19 changes: 0 additions & 19 deletions multiFilter.js
    Original file line number Diff line number Diff line change
    @@ -1,19 +0,0 @@
    /**
    * Filters an array of objects with multiple criteria.
    *
    * @param {Array} array: the array to filter
    * @param {Object} filters: an object with the filter criteria as the property names
    * @return {Array}
    */
    function multiFilter(array, filters) {
    const filterKeys = Object.keys(filters);
    // filters all elements passing the criteria
    return array.filter((item) => {
    // dynamically validate all filter criteria
    return filterKeys.every(key => {
    // ignores an empty filter
    if (!filters[key].length) return true;
    return filters[key].includes(item[key]);
    });
    });
    }
    26 changes: 0 additions & 26 deletions test.js
    Original file line number Diff line number Diff line change
    @@ -1,26 +0,0 @@
    let 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 },
    ];

    // the value of each key is an array with the values to filter
    let filters = {
    color: ["Blue", "Black"],
    size: [70, 50]
    };

    // filter the products array by color: blue and black
    // and also by size: 70 and 50
    var filtered = multiFilter(products, filters);

    console.info('Filtered:');
    console.log(filtered);

    /* expected
    [
    { name: "A", color: "Blue", "size": 50 },
    { name: "C", color: "Black", "size": 70 }
    ]
    */
  3. @jherax jherax revised this gist Feb 6, 2019. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion multiFilter.js
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,10 @@ function multiFilter(array, filters) {
    // filters all elements passing the criteria
    return array.filter((item) => {
    // dynamically validate all filter criteria
    return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
    return filterKeys.every(key => {
    // ignores an empty filter
    if (!filters[key].length) return true;
    return filters[key].includes(item[key]);
    });
    });
    }
  4. @jherax jherax revised this gist Mar 15, 2017. 2 changed files with 22 additions and 20 deletions.
    17 changes: 8 additions & 9 deletions multiFilter.js
    Original file line number Diff line number Diff line change
    @@ -1,16 +1,15 @@
    /**
    * Multi-filter an array of objects
    * @param {Array} array : list of elements to apply a multiple criteria filter
    * @param {Object} filters: Contains multiple criteria filters by the property names of the objects to filter
    * Filters an array of objects with multiple criteria.
    *
    * @param {Array} array: the array to filter
    * @param {Object} filters: an object with the filter criteria as the property names
    * @return {Array}
    */
    function multiFilter(array, filters) {
    let filterKeys = Object.keys(filters);
    const filterKeys = Object.keys(filters);
    // filters all elements passing the criteria
    return array.filter((item) => {
    // validates all filters criteria dynamically
    return filterKeys.every((key) => {
    return (filters[key].indexOf(item[key]) !== -1);
    });
    // dynamically validate all filter criteria
    return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
    });
    }
    }
    25 changes: 14 additions & 11 deletions test.js
    Original file line number Diff line number Diff line change
    @@ -1,23 +1,26 @@
    let products = [
    { name: "A", color: "Blue", size: 50 },
    { name: "B", color: "Blue", size: 60 },
    { name: "C", color: "Black", size: 70 }
    { name: "C", color: "Black", size: 70 },
    { name: "D", color: "Green", size: 50 },
    ];

    // the value of each key is an array with the values to filter
    let filters = {
    color: ["Blue", "Black"],
    size: [70, 50]
    };

    // expected
    let expected = [
    { name: "A", color: "Blue", "size": 50 },
    { name: "C", color: "Black", "size": 70 }
    ];

    // filter the products array by color: blue and black
    // and also by size: 70 and 50
    var filtered = multiFilter(products, filters);

    console.info('Expected');
    console.log(expected);
    console.info('Filtered');
    console.log(filtered);
    console.info('Filtered:');
    console.log(filtered);

    /* expected
    [
    { name: "A", color: "Blue", "size": 50 },
    { name: "C", color: "Black", "size": 70 }
    ]
    */
  5. @jherax jherax created this gist Sep 29, 2016.
    16 changes: 16 additions & 0 deletions multiFilter.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    /**
    * Multi-filter an array of objects
    * @param {Array} array : list of elements to apply a multiple criteria filter
    * @param {Object} filters: Contains multiple criteria filters by the property names of the objects to filter
    * @return {Array}
    */
    function multiFilter(array, filters) {
    let filterKeys = Object.keys(filters);
    // filters all elements passing the criteria
    return array.filter((item) => {
    // validates all filters criteria dynamically
    return filterKeys.every((key) => {
    return (filters[key].indexOf(item[key]) !== -1);
    });
    });
    }
    23 changes: 23 additions & 0 deletions test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    let products = [
    { name: "A", color: "Blue", size: 50 },
    { name: "B", color: "Blue", size: 60 },
    { name: "C", color: "Black", size: 70 }
    ];

    let filters = {
    color: ["Blue", "Black"],
    size: [70, 50]
    };

    // expected
    let expected = [
    { name: "A", color: "Blue", "size": 50 },
    { name: "C", color: "Black", "size": 70 }
    ];

    var filtered = multiFilter(products, filters);

    console.info('Expected');
    console.log(expected);
    console.info('Filtered');
    console.log(filtered);