30 行代码实现 iOS 商城商品多规格 SKU 组合算法
0x00 前言
最近公司的一个项目,要增加商城功能,并且可以让用户自己创建商品,可以是单规格的,也可以是多规格的。所以这里分享一下商品的多个规格,生成所有 SKU 组合是怎么实现的。写的时候也没想去网上找现成的,想自己试着实现下,感觉不会很难。
0x01 理清思路
如果是单组的情况,比如只有一个规格:颜色 ,这个规格有几个 SKU: [黑色,白色,红色] ,那么就不需要组合,所以先判断长度,为 1 就直接用,然后继续处理规格数量大于 1 的情况。
我们可以通过模拟几组数据,来找找规律。
先看两组的情况,比如:
规格A:[a0,a1,a2]
规格B:[b0,b1,b2]
先从 a0 开始,跟规格 B 里面的 3 个分别组合:
a0b0,a0b1,a0b2
然后是 a1:a1b0,a1b1,a1b2
最后是 a2:a2b0,a2b1,a2b2
再看三组的情况:
规格A:[a0,a1,a2]
规格B:[b0,b1,b2]
规格C:[c0,c1,c2]
还是 a0 开始,先跟b0组合,接着跟规格C里面的三个分别组合:
a0b0c0,a0b0c1,a0b0c2
然后返回上一层的规格B,用a0和b1组合之后再跟规格C里面的三个分别再组合:
a0b1c0,a0b1c1,a0b1c2
以此类推:
a0b2c0,a0b2c1,a0b2c2
当规格B里面的所有元素都组合完之后,再返回上一层,也就是规格A,下标加1,重复前面的操作,先跟b0组合,接着跟规格C里面的三个分别再组合:
a1b0c0,a1b0c1,a1b0c2
然后再以此类推,这样,我们大概就可以看出一些规律了。
0x02 寻找规律
既然是寻找规律,那么就不定死规格的数量了,假设有 N 个规格,而且每个规格里面的元素数量也不相同。
首先,先拎出第一个规格的数组 N0,作为一个起始,遍历里面的元素,也就是 for 循环,先用下标为 0 的元素 N0[0],跟下一个规格的数组 N1 的第一个元素 N1[0] 组合,如果还有下一层 N2,则继续跟 N2 的第一个元素 N2[0] 组合,直到最后一个规格的数组的第一个元素 N(n-1)[0],到这里,第一个 SKU 组合就完成了。
第二个组合,前面都是一样的,但是最后一个规格的数组,元素变成了第二个,也就是下标加 1。
第三个组合,也还是一样的,最后一个规格的数组,元素变成了第三个,也就是下标再加 1。
.
.
.
直到最后一个规格 N(n-1) 的数组,元素到了最后一个,遍历结束。
然后返回到上一个规格 N(n-2),下标加 1,然后和最后一个规格 N(n-1) 的各个元素分别再组合,组合结束之后,再次返回到 N(n-2),下标再加 1,直到 N(n-2) 的元素也到最后一个,相同的,再返回到上一个规格 N(n-3),直到 n = 1 时,元素也遍历完最后一个。
至此,N0 的第一次 for 循环结束,继续后面的循环。
下面来贴上代码,实操下。
0x03 算法代码
以下是算法,Swift 编写,可以复制到 Xcode 的 Playground 中运行
1 | // 传入一个二维数组,元素不一定是 String,可以是一个对象,对象里面存有规格的元素数组就行,可以自行扩展更改 |
每步都有注释,如果不算注释,空行,还有 log,实际的代码行数也就 30 行。
下面来测试一下这个算法,来写几个测试用例。
0x04 测试
测试用例0,没有数据:
1 | groupingSKU(withSpecs: [[]]) |
打印:
1 | "list.count = 0, should: 0" |
测试用例1,只有一组数据:
1 | groupingSKU(withSpecs: [["S", "M", "L", "XL", "XXL", "XXXL"]]) |
打印:
1 | "group: ["S", "M", "L", "XL", "XXL", "XXXL"]" |
测试用例2,两组数据:
1 | groupingSKU(withSpecs: [["S", "M", "L"], ["黑色", "白色", "红色"]]) |
打印:
1 | "group: ["S", "黑色"]" |
测试用例3,多组数据:
1 | groupingSKU(withSpecs: [["S", "M", "L", "XL"], ["黑色", "白色", "红色"], ["一件", "两件", "三件", "四件"]]) |
打印:
1 | "group: ["S", "黑色", "一件"]" |
测试用例4,多组数据,单个元素:
1 | groupingSKU(withSpecs: [["S"], ["黑色"], ["一件"]]) |
打印:
1 | "group: ["S", "黑色", "一件"]" |
测试用例5,多组数据,存在空元素的情况:
1 | groupingSKU(withSpecs: [["S"], [], ["一件"]]) |
打印:
1 | "group: ["S", "一件"]" |
测试全部通过。💯