本文介绍如何在 javascript 中实现带条件限制的笛卡尔积运算,支持基于参数索引和值的动态规则(如“当第 0 列为 2 时,第 1 列只能取 'a' 或 'b'”),通过预编译谓词函数 + 过滤策略高效生成合法组合。
在实际开发中,尤其是配置生成、参数化测试或表单联动场景,我们常需枚举多个维度的合法组合,但并非所有笛卡尔积结果都有效——某些参数值之间存在业务约束(例如:选择“iOS”系统时,版本号仅允许 15–17;选择“Android”时则只允许 11–14)。此时,一个支持条件过滤的笛卡尔积生成器就至关重要。
下面提供一种清晰、可扩展且性能可控的实现方案:
// 递归式笛卡尔积(尾递归优化版,支持任意长度数组)
const cartesian = ([xs, ...xss]) => {
const kids = xs && cartesian(xss);
return xs == undefined
? [[]]
: xs.flatMap(x => kids.map(ys => [x, ...ys]));
};
// 主函数:生成带条件约束的组合
const generateCombinations = (params, pairRestrictions) => {
// 将嵌套 restrictions 转换为谓词函数数组
const predicates = Object.entries(pairRestrictions).flatMap(
([k0, v0]) => Object.entries(v0).flatMap(
([k
1, v1]) => Object.entries(v1).flatMap(
([k2, v2]) => (xs) =>
xs[Number(k0)] == k1 ? v2.includes(xs[Number(k2)]) : true
)
)
);
// 生*量组合并过滤
return cartesian(params).filter(combination =>
predicates.every(predicate => predicate(combination))
);
};const params = [[1, 2, 3], ["A", "B", "C"], [10, 11, 12]];
const pairRestrictions = { 0: { 2: { 1: ["A", "B"] } } };
const result = generateCombinations(params, pairRestrictions);
console.log(result.length); // → 24(原 27 组中排除了 [2,'C',*] 和 [3,'C',*] 共 3 组)✅ 注意:上述约束含义为:若第 0 个参数取值为 2,则第 1 个参数必须属于 ["A","B"]。由于 pairRestrictions[0][2] 显式定义了 2 的约束,而 1 和 3 未声明,因此默认允许任意值(即谓词返回 true)。
本方案以函数式思维解耦“组合生成”与“条件验证”,结构清晰、易于调试与扩展。它不侵入原始笛卡尔积逻辑,而是通过高阶函数组合实现关注点分离,既保持了算法的通用性,又赋予其强大的业务适配能力——真正做到了「用数据描述规则,用函数执行逻辑」。