0

I am currently writing a class to filter objects within an array. One of the internal methods of this class needs to test to see if a specific property satisfies any of the 'ranges' passed in an array.

Consider the following filter object:

const filters = {
    duration: ['<30', '>30<60', '>300<900', '>900<1800', '>1800', '>60<300']
};

Now consider the following items array (and objects):

const items = [
    {
        duration: 10
    },
    {
        duration: 500
    },
    {
        duration: 10000
    }
];

I need to write a function that will dynamically generate the tests that will compare the value of items[x].duration to each of the ranges defined in filters.duration.

Using the above data as an example, the expected result would be:

[
    {
        duration: 10
    },
    {
        duration: 500
    }
];

I already have the logic for applying the filters. This is what I have so far:

/**
 * Filter the item by duration.
 *
 * @param {object} item
 * @param {array} values
 * @returns {boolean}
 */
_filterByDuration(item, values) {

    // NOTES FOR SO:
    // `item` represents the item to test
    // `values` represents the supplied range e.g. ['<30', '>1800', '>60<300']

    // If any of them match then return `true`
    return values.some( range => {

        range = this._rangeHelper(range);

        // Stuck here...
        // Need to test `item.duration` against the `range` values

    });

}

/**
 * Extract a testable range from the supplied string.
 *
 * @param {string} range
 * @returns {object}
 */
_rangeHelper(range) {

    // Can't decide whether to return an object/array
    // Most likely need a regex to build the dynamic
    // range

}

Update 1

Thinking more about this, I think the best method is to extract the range from the supplied range strings and return an object like so:

{
    min: 0,
    max: 0
}

With this in mind, _rangeHelper should return the following:

For <20:

{
    max: 20
}

For <1800:

{
    min: 1800
}

For >60<300:

{
    min: 60,
    max: 300
}

I think this will then make it fairly simply to just test between the ranges using the range.min and range.max values.

Update 2

Might be guilty of answering my own question shortly... Still keen to hear other ideas though. This is my latest update:

/**
 * Extract a testable range from the supplied string.
 *
 * @param {string} range
 * @returns {object}
 */
_rangeHelper(range) {

    const min = range.match(/>(\d+)/);
    const max = range.match(/<(\d+)/);

    return {
        min: min && typeof min[1] !== 'undefined' ? min[1] : null,
        max: max && typeof max[1] !== 'undefined' ? max[1] : null
    };

}
2
  • I'm not sure where these filters are comming from "database" or "hardcoded" but if they're hard coded you could make them functions instead like this const filters = [ (x) => x < 60, (x) => x < 50 && x > 100] I've just made up some functions here but you could put anything you like in those functions Commented Jun 18, 2020 at 0:49
  • 2
    @MaxCarroll - Unfortunately not as simple as that - the ranges are dynamically generated. Not a problem though as I have basically solved it. I'll leave the question up in case anyone has begun to write an answer - keen to see what other's come up with Commented Jun 18, 2020 at 0:51

1 Answer 1

2

Consider this:

let value = 70;
let filters = ['<30', '>30<60', '>300<900', '>900<1800', '>1800', '>60<300'];

function matchRange(value, range){
    const edges = range.match(/[\<\>]\d*/g);

    return edges.every(edge => {
        const [, comp, num] = edge.match(/([\<\>])(\d*)/);
        return comp == '>' ? value > Number(num) : value < Number(num); 
    })
}

filters.some( range => matchRange( value, range ) );
Sign up to request clarification or add additional context in comments.

1 Comment

This is an interesting answer - slightly different to mine but still achieves the same. +1 and will accept :-D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.