谁说前端没算法 | 您所在的位置:网站首页 › sku是 › 谁说前端没算法 |
什么是SKU
sku就是我们在京东或者拼多多购物的时候,选择的商品的属性。 通过动态图很容易明白什么是sku是什么,就是选择一件商品的不同属性。 从图中我们可以看到可选的sku有男裤黑色L、男裤白色L、女裤白色S、女裤白色L. SKU中的概念 类型 : 类型就是上图中可选择的每一行数据,比如上图中就包含三个类型 [ // 第一种类型 [男裤,女裤], // 第二种类型 [黑色,白色], // 第三种类型 [S,L], ]规格: 规格就是上图中的每个可以选择的属性,比如上图中的类型的综合,也就是 [男裤,女裤,黑色,白色,S,L]可选择的SKU: 因为不是每件商品的规格都可以选择,比如上图中男裤白色S,就是不可选的sku,可选的sku有4种,如下: SKU 算法难点是在哪里呢? 我们可以想一下,如果是我们实现,我们会如何实现该功能呢? 难就难在当我们选择某个规格以后,如何确定还有哪些规格是可以选择的,比如选择了规格S以后,男裤和黑色就需要置灰,不能选择了,因为目前男裤黑色S的SKU是没有的。 所以难点就是当点击某个规格以后,所有的规格都需要重新计算一遍,以便确定规格是否可点或者disabled掉。 通过上面的分析,问题就转换为当选择了某个规格后,如何通过可选的SKU查找出哪些规格还可以点击或者哪些规格需要被disabled 掉。 SKU质数算法 SKU质数算法使用的数据例子 // type: 规格类型,每个规格是指type中的一个值,比如男裤,女裤,黑色,白色等 type: [ ["男裤", "女裤"], ["黑色", "白色"], ["S", "L"], ], // 可选的SKU const canUseSku = [ { // 当前SKU的可选数量 stock: 1, // 当前SKU包含的规格 skuName: ["男裤", "黑色", "L"], // 当前SKU包含的规格对应的质数 skuPrime: [2, 5, 13], }, { stock: 1, skuName: ["男裤", "白色", "L"], skuPrime: [2, 7, 13], }, { stock: 1, skuName: ["女裤", "白色", "S"], skuPrime: [3, 7, 11], }, { stock: 1, skuName: ["女裤", "白色", "L"], skuPrime: [3, 7, 13], }, ]; 为什么选择质数因为质数只有1和自身,比如有一个数组里边都包含质数,比如有一个数组[2,5,7],那么此时如果我们通过把数组里边元素相乘, 得到2 * 5 * 7。 此时我们就很容易判断数组[2], [2,5,7],[2,5], 里边的元素是不是都在数组[2,5,7]中, 因为2 * 5 * 7 / 2 可以整除 2 * 5 * 7 / (2 * 5 * 7) 可以整除 2 * 5 * 7 / (2 * 5)可以整除 同时也很容易判断数组[2,3]里边不是所有的元素不是都在数组[2,5,7]中, 因为 2 * 5 * 7 / (2 * 3)不可以整除。 所以可以把规格和可选SKU都转成质数,通过这种方式来判断规格是否在可选的SKU里边,例如 type: [ // 一种规格类型,男裤是一种规格 ["男裤", "女裤"], // 一种规格类型 ["黑色", "白色"], ["S", "L"], ],这里边有三种规格类型,6种规格,那么如果把每个规格,按照质数从小到大转换,那就是 // ["男裤", "女裤", "黑色", "白色","S", "L"], [2,3,5,7,11,13]此时可选的SKU有 ["男裤", "黑色", "L"],["男裤", "白色", "L"],["女裤", "白色", "S"],,["女裤", "白色", "L"],那么此时可选的SKU对应的质数就可以得出 [2, 5, 13],[2, 7, 13],[3, 7, 11],[3, 7, 13]此时如果把可选的SKU对应的质数相乘,就会得到 [2 * 5 * 13, 2 * 7 * 13 , 3 * 7 * 11,3 * 7 * 13]当所有规格都转成质数,所有的可选SKU都转成质数以后,就可以通过质数的方法来根据当前已经选择的规格,查看其它规格是否可选或者需要disabled掉了。 SKU算法实现整个问题,就已经被转换为质数问题了。 原来的问题是当选择某个规格,需要根据可选的SKU,重新计算那些规格可以选择? 现在已经转换为当选择了某个质数,需要根据可选的SKU对应的质数数组,重新计算还有哪些质数可以重新选择。 那么此时就有问题了,那么如何判断某个质数,是不是可以选择呢? ——————————可以先思考一下😁—————————————————— 其实可以通过查看可选的SKU对应的质数数组,查看当前的质数能否被整除,当某个质数能够被整除,就说明该质数对应的规格是可以被选择的。 比如刚开始的时候,肯定是没有任何一个质数已经被选择了,所以可以设置初始值为1,然后遍历所有的质数,就会发现 [2,3,5,7,11,13] 这些质数都可以被选择,也就是这些质数对应的规格都可以被选择,也就是男裤、女裤、黑色、白色、S、L都可以被选择。 为什么呢? 因为[2,3,5,7,11,13] 这些质数,可以被可选择的SKU质数集合,也就是[2 * 5 * 13, 2 * 7 * 13 , 3 * 7 * 11,3 * 7 * 13]整除。 所以此时初始化的时候,哪些规格可以选择的问题,就已经解决了。 下面来处理当我们选择了某个规格的情况: 假设当选择了黑裤,也就是质数2被选中的时候,此时已经被选择的规格数组就是[2], 此时就需要再次遍历所有的规格,确定当前的规格是否可以被选择。 此时需要处理两种情况。 第一种: 规格和当前选择的规格是同一种规格类型的时候,此时就需要在已经选择的规格数组中替换掉原来已经选择的规格。 比如现在已经选择了男裤,但是如果看女裤是不是可以选择的时候,此时就需要把已经被选择的规格数组[2],变成 [3] (女裤对应的规格质数是3),此时再利用[3]去遍历可选择的SKU质数集合,也就是[2 * 5 * 13, 2 * 7 * 13 , 3 * 7 * 11,3 * 7 * 13],此时发现3是可以被选择的,因为3是可以被可选择的SKU质数集合[2 * 5 * 13, 2 * 7 * 13 , 3 * 7 * 11,3 * 7 * 13]中某一项整除的。 第二种: 规格不和已经选择的规格质数数组存在同一种类型的,比如目前选择了黑裤[2], 那么此时直接把规格添加到已经选择的规格质数数组,然后再查看当前规格是否可选就可以了。 比如规格质数5、7,13 可以发现5、7、13都是可以选择的。 为什么呢? 因为2 * 5、2 * 7、2 * 13都是可以被可选择的SKU质数数组[2 * 5 * 13, 2 * 7 * 13 , 3 * 7 * 11,3 * 7 * 13]中某一项整除的。 所以通过上面两种情况,当选择了男裤,也就是质数2以后,3、5、7,13 都可以被选择。 同理当选择了[2, 5] 以后,可选择的规格变成了7, 13了 3不能选择的原因是3 * 5 不能被可选择的SKU质数数组[2 * 5 * 11, 2 * 7 * 13 , 3 * 7 * 11, 3 * 7 * 13]中任何一项整除的。 同理11一样的道理。 优化其实应该还可以进行优化,还是按照前面的思路, 假设目前规格有[2,3,5,7,11,13],一共这6种规格,此时此时可选的SKU数组变成有[2 * 7 * 11, 2 * 7 * 13 , 3 * 5 * 13] 那么此时其实可以提前先把所有的规格选择都计算出来,使用一个map缓存结果。 比如其中一条可选的SKU, 男裤白色S, 此时对应的质数为 2 、7、11, 可以这么看,此时的SKU为 [2, 7, 11], 假设库存量是1 那么此时可以认为 (* 代表任何规格) [2, *, *] 的库存量为1 [*, 7, *] 的库存量为1 [*, *, 11] 的库存量为1 [2, 7, *] 的库存量为1 [2, *, 11] 的库存量为1 [*, 7, 11] 的库存量为1 [2, 7, 11] 的库存量为1 那么此时可以把* 认为是1 此时可以转换为对象如下 { // 2 * 1 * 1: 1, 2: 1, 7: 1, 11: 1, 14: 1, 22: 1, 77: 1, 154:1 }同理另外一条SKU [2, 7, 13], 也可以转换为 { // 2 * 1 * 1: 1, 2: 1, 7: 1, 13: 1, 14: 1, 26: 1, 91: 1, 182:1 }同理另外一条SKU [3, 5, 13], 也可以转换为 { // 3 * 1 * 1: 1, 3: 1, 5: 1, 13: 1, 15: 1, 3 * 13: 1, 5 * 13: 1, 3 * 5 * 13:1 }如果把所有的SKU转换的对象合并那么就是 { // 2 * 1 * 1: 1, 2: 2, 3: 1, 5: 1, 7: 2, 11: 1, 13: 2, // 3 * 5 : 1 15: 1, // 2 * 7: 1 14: 2, // 2 * 11: 1 22: 1, // 2 * 13: 1 26: 1, // 3 * 13: 1, 39: 1, // 5 * 13: 1, 65: 1, // 7 * 11 :1 77: 1, // 7 * 13 : 1 91: 1, // 2 * 7 * 11 :1 154:1, // 2 * 7 * 13 : 1 182:1, // 3 * 5 * 13:1 195:1 }所以此时有了这个可选的对象,一切都变得很容易了。 这个可选的对象命名为itemMap 初始化的时候,遍历所有的规格,比如2、3、5、7、11、13,如果发现在itemMap中存在,那么就是可选的。 比如 2、3、5、7、11、13 都在itemMap中,所以这些对应的规格都是可选的。 当选择了其中一个规格,再选下一个的时候,也是查看是否在itemMap中, 比如当选择了男裤,也就是质数2的时候,此时如果想查看女裤是否可选,因为女裤和男裤是同一规格类型,所以此时应该是查看女裤对应的质数3是否是在itemMap中,如果在则是可选的,可以发现3是可选的。 当查看黑色是否可选的时候,因为黑色对应的质数是5,所以此时需要查看男裤黑色,也就是27 是不是在itemMap中,此时发现2 * 7 在itemMap中,所以此时黑色是可选的。其它规格同理可计算出。 当选择了男裤*黑色后,此时已经选择的质数就是2 * 5了,此时也需要查看,还有哪些规格可选, 比如此时查看女裤,因为女裤对应的质数是3,同时女裤和男裤是同一种规格类型,此时就要查看 3 * 5 是不是在itemMap中,可以发现3 * 5 在itemMap中,所以女裤可选。 同理白色对应的质数是7,那么此时就要查看2 * 7是不是在itemMap中,发现2 * 7 在 itemMap 中,所以白色也是可选的。 但是S对应的质数是11,因为 2 * 5 * 11 不在itemMap中,所以此时S不可选 L对应的质数是13,因为 2 * 5 * 13 也不在itemMap中,所以此时L也不可选。 整体思路 就是根据已经选择的规格,重新去查看其它的规格,根据可选的SKU,来决定当前规格是否可选。 其它实现方式有的解法是使用无向图来解决,但是但是无向图无法解决边公用的问题,就是比如有a1,a2,b1,b2,c1,c2 六种规格,当可选的SKU是 [a1 * b1 *c1, a1 * b2 * c2, a2 * b1 * c2] 的时候,也会把 a1 * b1 * c2 认为是合法的SKU. 参考与源码电商最小存货 - SKU 和 算法实现 GITHUB 源码 |
CopyRight 2018-2019 实验室设备网 版权所有 |