根据范围数组动态过滤对象数组

时间:2020-06-18 00:20:46

标签: javascript arrays object filter

我目前正在编写一个类来过滤数组中的对象。此类的内部方法之一需要进行测试,以查看特定属性是否满足数组中传递的任何“范围”。

考虑以下过滤器对象:

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

现在考虑以下项数组(和对象):

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

我需要编写一个函数,该函数将动态生成将items[x].duration的值与filters.duration中定义的每个范围进行比较的测试。

以上述数据为例,预期结果将是:

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

我已经有了应用过滤器的逻辑。这是我到目前为止所拥有的:

/**
 * 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

}

更新1

对此进行更多思考,我认为最好的方法是从提供的范围字符串中提取范围并返回一个对象,如下所示:

{
    min: 0,
    max: 0
}

考虑到这一点,_rangeHelper应该返回以下内容:

对于<20

{
    max: 20
}

对于<1800

{
    min: 1800
}

对于>60<300

{
    min: 60,
    max: 300
}

我认为这样就可以相当简单地使用range.minrange.max值在范围之间进行测试。

更新2

很快就会回答我自己的问题而感到内...……尽管仍然很想听听其他想法。这是我的最新更新:

/**
 * 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
    };

}

1 个答案:

答案 0 :(得分:2)

考虑一下:

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 ) );