故事的起源都从我看到这么一个问题开始:
let names = ["iPhone X", "iPhone XS"]
let colors = ["黑色", "白色"]
let storages = ["64g", "256g"]
有这么几个数组,列出他们的所有组合,最终出来的结果像这样:
[
["iPhone X", "黑色", "64g"],
["iPhone X", "黑色", "256g"],
["iPhone X", "白色", "64g"],
["iPhone X", "白色", "256g"],
["iPhone XS", "黑色", "64g"],
["iPhone XS", "黑色", "256g"],
["iPhone XS", "白色", "64g"],
["iPhone XS", "白色", "256g"],
]
这个问题的难点在于上面的数组个数是可以增删的,所以不能粗暴地根据上面3个数组就直接3重循环来解决。
大家可以先在这里暂停一下,自己思考下解决方案。
解决方案
我自己花了半个小时把代码写出来了,但是发现没大佬写的那么优雅,所以这里借用一下大佬的解决方案放上来给大家参考。
let names = ["iPhone X", "iPhone XS"]
let colors = ["黑色", "白色"]
let storages = ["64g", "256g"]
let combine = function (...chunks) {
let res = []
let helper = function (chunkIndex, prev) {
let chunk = chunks[chunkIndex]
let isLast = chunkIndex === chunks.length - 1
for (let val of chunk) {
let cur = prev.concat(val)
if (isLast) {
// 如果已经处理到数组的最后一项了 则把拼接的结果放入返回值中
res.push(cur)
} else {
helper(chunkIndex + 1, cur)
}
}
}
// 从属性数组下标为 0 开始处理
// 并且此时的 prev 是个空数组
helper(0, [])
return res
}
console.log(combine(names, colors, storages))
作者:晨曦时梦见兮
链接:https://juejin.im/post/5ee6d9026fb9a047e60815f1
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
大家有兴趣的话也可以看下「前端电商 sku 的全排列算法很难吗?学会这个套路,彻底掌握排列组合」这篇文章,里面也有作者的解决思路和扩展知识分享。
扩展
查阅了其他资料之后,发现这类题目属于笛卡尔积问题,**画重点,笛卡尔积问题~****,**在stackoverflow上还有一个大佬的极简解法,这里也放上来给大家欣赏。
const f = (a, b) => [].concat(...a.map(d => b.map(e => [].concat(d, e))));
const cartesian = (a, b, ...c) => (b ? cartesian(f(a, b), ...c) : a);
let output = cartesian([1,2],[10,20],[100,200,300]);
输出output
[ [ 1, 10, 100 ],
[ 1, 10, 200 ],
[ 1, 10, 300 ],
[ 1, 20, 100 ],
[ 1, 20, 200 ],
[ 1, 20, 300 ],
[ 2, 10, 100 ],
[ 2, 10, 200 ],
[ 2, 10, 300 ],
[ 2, 20, 100 ],
[ 2, 20, 200 ],
[ 2, 20, 300 ] ]
你没看错,就两行代码解决了,大佬请收下我膝盖,真牛B。文章在这里:Cartesian product of multiple arrays in JavaScript,感兴趣可以看看。