前言

做过电商项目前端售卖的应该都遇见过不同规格产品库存的计算问题,业界名词叫做sku(stock Keeping Unit),库存量单元对应我们售卖的具体规格,比如一部手机具体型号规格,其中iphone6s 4G 红色就是一个sku。这里我们区别spu(Standard Product Unit),标准化产品单元,比如一部手机型号iphone6s就是一个spu

sku 算法

在前端展示商品时,根据用户选择的不同sku,我们需要计算出不同的库存量动态展示给用户,这里就衍生出了sku算法。

数据结构

我们先看看在后端服务器保存库存的数据结构一般是长怎么样的:

  1. // 库存列表
  2. const skuList = [
  3. {
  4. skuId: '0',
  5. skuGroup: ['红色', '大'],
  6. remainStock: 7,
  7. price: 2,
  8. picUrl: 'https://dummyimage.com/100x100/ff00b4/ffffff&text=大'
  9. },
  10. {
  11. skuId: '1',
  12. skuGroup: ['红色', '小'],
  13. remainStock: 3,
  14. price: 4,
  15. picUrl: 'https://dummyimage.com/100x100/ff00b4/ffffff&text=小'
  16. },
  17. {
  18. skuId: '2',
  19. skuGroup: ['蓝色', '大'],
  20. remainStock: 0,
  21. price: 0.01,
  22. picUrl: 'https://dummyimage.com/100x100/0084ff/ffffff&text=大'
  23. },
  24. {
  25. skuId: '3',
  26. skuGroup: ['蓝色', '小'],
  27. remainStock: 1,
  28. price: 1,
  29. picUrl: 'https://dummyimage.com/100x100/0084ff/ffffff&text=小'
  30. }
  31. ];
  32. // 规格列表
  33. const skuNameList = [
  34. {
  35. skuName: "颜色",
  36. skuValues: ["红色", "蓝色"]
  37. },
  38. {
  39. skuName: "尺寸",
  40. skuValues: ["大", "小"]
  41. }
  42. ];

算法演示

在前端用户选择单个规格或多个规格后,我们需要动态计算出此时其他按钮是否还能点击(组合有库存),以及当前状态对应的总库存量,封面图和价格区间。

以上面的数据举个

开始时什么都没有选择,展示默认图片,规格列表中的第一项组合(['红色-大'])对应的图片,库存为商品总库存,价格为商品的价格区间。然后在用户选择某个属性或几个属性的时候实时计算对应的图片,库存,价格区间。

同时根据当前已选属性,置灰不可选择的属性。在本例中,蓝色 大的产品对应的库存为 0,所以当我们选择其中一项 蓝色 或者 大 的时候,需要置灰另一个属性选项。

实现思路-第一种算法

为了大家能看清下面的分析,在此定义下相关名词,库存列表:skuList,规格列表:skuNameList,属性:skuNameList-skuValues数组下的单个元素,规格:skuNameList下的单个元素

sku 算法的难点在于如何根据当前已选属性(未选,选择部分,全选)来判断当前其它属性是否可选

在网上查找相关算法时比较广泛流传的是来自淘宝前端的两种算法,下面将实现第一种算法:

主要思路就是遍历当前的规格列表下的属性,根据已选属性及库存列表判断当前属性按钮是否有库存(可选):

  • 将规格列表下的已选属性集合作为入参 selected,如果在当前规格未选择相关属性则传入空字符串,即最开始时 selected === ['', '']

  • 初始化相关变量,库存,价格区间,图片,及属性对象attrState(attrState 用于标记每个属性是否可选)

  • 遍历规格列表,移除存在与当前规格属性数组中已选属性(假设当前规格未选择)

  • 遍历规格属性,依次将当前属性和已选属性组合

  • 将上步的组合作为最终属性组合,遍历库存列表是否存在库存(属于子集关系且库存>0),有库存则标记可选(true)

  • 最后再次遍历库存列表,用来获取当前库存,图片,价格等 sku 数据

  1. /**
  2. * 获取sku信息
  3. * @param {Array} selected 已选属性数组
  4. * @return {Object} skuInfo
  5. *
  6. */
  7. const getSkuInfo = (selected) => {
  8. // 用以记录每个按钮状态的,例如 itemState['红色'] = true 表示高亮
  9. const attrState = {};
  10. let picUrl = '';
  11. let minPrice = Number.MAX_VALUE;
  12. let maxPrice = 0;
  13. let remainStock = 0;
  14. // in array not in others
  15. const difference = (array, others) => {
  16. return array.filter((item) => others.indexOf(item) === -1);
  17. };
  18. // every in array in others
  19. const isSubset = (array, others) => {
  20. return array.every((item) => others.indexOf(item) > -1);
  21. };
  22. // 遍历规格列表
  23. skuNameList.forEach((spec) => {
  24. // 移除当前遍历规格下的已选属性
  25. const tempSelected = difference(selected, spec.skuValues).filter(name => name);
  26. // 遍历规格属性
  27. spec.skuValues.forEach((name) => {
  28. const willSelected = [...tempSelected, name];
  29. // 默认无库存不可选
  30. attrState[name] = false;
  31. // 在库存列表寻找匹配库存
  32. for (let i = 0, len = skuList.length; i < len; i++) {
  33. const skuGroup = skuList[i].skuGroup;
  34. if (isSubset(willSelected, skuGroup) && skuList[i].remainStock) {
  35. attrState[name] = true;
  36. break;
  37. }
  38. }
  39. });
  40. });
  41. // 实际已选属性,过滤空字符串
  42. const realSelected = selected.filter((item) => item);
  43. // 默认选择用于匹配当前图片
  44. const defaultSelected = selected.map(
  45. (name, idx) => name || skuNameList[idx].skuValues[0]
  46. );
  47. skuList.forEach((sku) => {
  48. if (isSubset(realSelected, sku.skuGroup)) {
  49. remainStock += sku.remainStock;
  50. maxPrice = maxPrice > sku.price ? maxPrice : sku.price;
  51. minPrice = minPrice < sku.price ? minPrice : sku.price;
  52. // 取当前图片
  53. if (isSubset(defaultSelected, sku.skuGroup)) {
  54. picUrl = sku.picUrl;
  55. }
  56. }
  57. });
  58. return {
  59. attrState,
  60. picUrl,
  61. minPrice,
  62. maxPrice,
  63. remainStock,
  64. };
  65. };

总结

做过电商项目的应该都处理或者听说过sku,学习相关概念和真正理解如何计算sku可以帮助我们更加熟悉业务,提升自己对于相关业务的处理能力。以后在面试中遇到面试官的提问也能更稳一些。后面将介绍第二种算法,其思路更容易理解,也是比较多同学在业务中采用的方式。

参考


欢迎到前端学习打卡群一起学习~516913974

sku算法介绍及实现的更多相关文章

  1. 【原创】机器学习之PageRank算法应用与C#实现(1)算法介绍

    考虑到知识的复杂性,连续性,将本算法及应用分为3篇文章,请关注,将在本月逐步发表. 1.机器学习之PageRank算法应用与C#实现(1)算法介绍 2.机器学习之PageRank算法应用与C#实现(2 ...

  2. KNN算法介绍

    KNN算法全名为k-Nearest Neighbor,就是K最近邻的意思. 算法描述 KNN是一种分类算法,其基本思想是采用测量不同特征值之间的距离方法进行分类. 算法过程如下: 1.准备样本数据集( ...

  3. ISP基本框架及算法介绍

    什么是ISP,他的工作原理是怎样的? ISP是Image Signal Processor的缩写,全称是影像处理器.在相机成像的整个环节中,它负责接收感光元件(Sensor)的原始信号数据,可以理解为 ...

  4. Python之常见算法介绍

    一.算法介绍 1. 算法是什么 算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制.也就是说,能够对一定规范的输入,在有限时间内获得所要求的输 ...

  5. RETE算法介绍

    RETE算法介绍一. rete概述Rete算法是一种前向规则快速匹配算法,其匹配速度与规则数目无关.Rete是拉丁文,对应英文是net,也就是网络.Rete算法通过形成一个rete网络进行模式匹配,利 ...

  6. H2O中的随机森林算法介绍及其项目实战(python实现)

    H2O中的随机森林算法介绍及其项目实战(python实现) 包的引入:from h2o.estimators.random_forest import H2ORandomForestEstimator ...

  7. STL 算法介绍

    STL 算法介绍 算法概述 算法部分主要由头文件<algorithm>,<numeric>和<functional>组成.        <algorithm ...

  8. Levenshtein字符串距离算法介绍

    Levenshtein字符串距离算法介绍 文/开发部 Dimmacro KMP完全匹配算法和 Levenshtein相似度匹配算法是模糊查找匹配字符串中最经典的算法,配合近期技术栏目关于算法的探讨,上 ...

  9. 机器学习概念之特征选择(Feature selection)之RFormula算法介绍

    不多说,直接上干货! RFormula算法介绍: RFormula通过R模型公式来选择列.支持R操作中的部分操作,包括‘~’, ‘.’, ‘:’, ‘+’以及‘-‘,基本操作如下: 1. ~分隔目标和 ...

随机推荐

  1. C. Ilya And The Tree 树形dp 暴力

    C. Ilya And The Tree 写法还是比较容易想到,但是这么暴力的写法不是那么的敢写. 就直接枚举了每一个点上面的点的所有的情况,对于这个点不放进去特判一下,然后排序去重提高效率. 注意d ...

  2. STL下<algorithm>下的reverse函数

    定义: reverse用于C++中,对给定区间所有元素进行排序,是一种反向函数,不具备排序功能.sort函数包含在头文件为#include<algorithm>的C++标准库中. 语法: ...

  3. 201771010113 李婷华 《面向对象程序设计(java)》第九周总结

    一.理论知识部分 第六章 接口与内部类 1.内部类(innerclass)是定义在一个类内部的类.外层的类成为外部类(outerclass).内部类主要用于事件处理. 2.使用内部类的原因有以下三个: ...

  4. Vue + Element-ui实现后台管理系统(3)---面包屑 + Tag标签切换功能

    面包屑 + Tag标签切换功能 有关后台管理系统之前写过两遍博客,看这篇之前最好先看下这两篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system 1.V ...

  5. 【Spark】RDD(Resilient Distributed Dataset)究竟是什么?

    目录 基本概念 官方文档 概述 含义 RDD出现的原因 五大属性 以单词统计为例,一张图熟悉RDD当中的五大属性 解构图 RDD弹性 RDD特点 分区 只读 依赖 缓存 checkpoint 基本概念 ...

  6. Java三大特征:封装 继承 多态

    内部类:成员内部类.静态内部类.方法内部类.匿名内部类. 内部类:定义在另外一个类里面的类,与之对应,包含内部类的外部类被称为外部类. 内部类的作用:(1)内部类提供了更好的封装,可以把内部类隐藏在外 ...

  7. db连接池

    目前常用的连接池有: DBCP:org.apache.commons.dbcp.BasicDataSource dataSource: 要连接的 datasource (通常我们不会定义在 serve ...

  8. PMS学习

    一,PMS的adb相关重要指令 1,adb shell dumpsys package(dump所有的系统内apk信息) 2,adb shell dumpsys package “com.androi ...

  9. 1.3Go环境搭建之Windows

    1.1.2. Golang SDK SDK 的全称(Software Development Kit 软件开发工具包) 2) SDK是提供给开发人员使用的,其中包含了对应开发语言的工具包 1.1.3. ...

  10. 03 返回静态文件的高级web框架

    03 返回静态文件的高级web框架 服务器server端python程序(高级版): import socket server=socket.socket() server.bind(("1 ...