JavaScript如何优雅实现价格区间交集过滤商品数组
带null边界的价格区间商品过滤实现优化
我有一个存储商品信息的数组,每个商品包含name字段与prices价格区间字段,价格区间格式为[from, to],元组中的null代表对应方向无价格边界:
[null, 200]表示商品最高价格为200、无最低价格限制[200, null]表示商品最低价格为200、无最高价格限制
商品数组示例如下:
const goods = [ { name: "Sweets", prices: [0, 100] }, { name: "Chocolate", prices: [500, null] }, { name: "Cheesecake", prices: [100, 200] }, { name: "Truffle", prices: [null, null] }, { name: "Apple cake", prices: [null, 400] }, { name: "Banana cake", prices: [50, 250] }, { name: "Raspberry cake", prices: [200, null] }, { name: "Donuts", prices: [51, 450] }, ];
待使用的多组筛选价格区间:
const requiredRange1 = [null, 200]; const requiredRange2 = [100, 350]; const requiredRange3 = [200, null]; const requiredRange4 = [200, 300]; const requiredRange5 = [1000, null];
例如使用requiredRange1作为筛选条件时,预期输出结果为:
[ { name: "Sweets", prices: [0, 100] }, { name: "Cheesecake", prices: [100, 200] }, { name: "Apple cake", prices: [null, 400] }, { name: "Banana cake", prices: [50, 250] }, { name: "Raspberry cake", prices: [200, null] }, { name: "Donuts", prices: [51, 450] }, ]
现有实现问题
当前编写的过滤函数分支判断较多、存在硬编码问题,代码如下:
const filterCourses = (arrayOfCourses, requiredRange) => { const [minRequiredPrice, maxRequiredPrice] = requiredRange; const filterCallback = (course) => { const maxCoursePrice = course.prices[1]; const minCoursePrice = course.prices[0]; if(minCoursePrice === null && maxCoursePrice === null) { return false } if(minRequiredPrice === null) { return maxRequiredPrice >= minCoursePrice } else if(maxRequiredPrice === null) { return minRequiredPrice <= maxCoursePrice || minCoursePrice >= minRequiredPrice } else { return (minRequiredPrice > maxCoursePrice && maxCoursePrice !== null) || (maxRequiredPrice < minCoursePrice && minCoursePrice !== null) ? false : true } } const result = arrayOfCourses.filter(filterCallback) return result }
核心需求是找到更优雅简洁的实现方式,正确完成两个带null边界的价格区间的交集判断。
优化实现方案
区间交集判断的核心逻辑非常简单:两个区间存在交集的充要条件是,一个区间的左边界不大于另一个区间的右边界。处理null边界时只需要把无下界替换为-Infinity,无上界替换为Infinity,就可以完全消除分支判断。
优化后的代码如下:
/** * 过滤价格区间存在交集的商品 * @param {Array} goodsList 商品数组 * @param {[number|null, number|null]} filterRange 筛选价格区间 * @returns 符合条件的商品数组 */ const filterGoodsByPrice = (goodsList, filterRange) => { // 将null边界替换为无穷大/小,统一数值判断逻辑 const [filterMin, filterMax] = filterRange.map((val, idx) => val ?? (idx === 0 ? -Infinity : Infinity) ); return goodsList.filter(goods => { // 跳过prices字段不合法的空项 if (!goods || !Array.isArray(goods.prices)) return false; const [goodsMin, goodsMax] = goods.prices.map((val, idx) => { if (val === null) return idx === 0 ? -Infinity : Infinity; return val; }); // 上下边界都为null的商品无明确价格范围,按照原有逻辑排除 if (goodsMin === -Infinity && goodsMax === Infinity) return false; // 通用交集判断:区间左边界的最大值 <= 区间右边界的最小值 则存在交集 const intersectMin = Math.max(filterMin, goodsMin); const intersectMax = Math.min(filterMax, goodsMax); return intersectMin <= intersectMax; }); };
逻辑说明
- 边界统一转换:把所有
null的下边界替换为负无穷-Infinity,null的上边界替换为正无穷Infinity,不需要写大量分支判断null的场景 - 交集判断复用通用数学规则:两个区间
[a1, a2]和[b1, b2]存在交集的唯一判断条件是max(a1, b1) <= min(a2, b2),不需要额外处理边界场景 - 兼容原有逻辑中「商品价格上下边界都为
null时直接排除」的规则 - 额外增加了空项、字段缺失的容错判断,避免原数组中多余逗号导致的空元素引发运行报错
可以直接用给出的测试用例验证:
- 传入
requiredRange1 = [null, 200]时,返回结果和预期完全一致 - 传入
requiredRange5 = [1000, null]时,所有商品最高价格都小于1000,返回空数组,符合预期 - 传入
requiredRange3 = [200, null]时,会返回价格上限不低于200的商品,符合筛选要求
内容的提问来源于stack exchange,提问作者iannvrsk
相关产品推荐
相关产品推荐

