问题场景
SKU最小存货单位(Stock Keeping Unit)在连锁零售门店中有时称单品为一个SKU,定义为保存库存控制的最小可用单位,例如纺织品中一个SKU通常表示规格、颜色、款式。
逛过淘宝的人都知道一种商品可能有多种属性类型,拿一件衣服来说,
- 性别:男、女
- 颜色:红、绿、蓝
- 尺寸上:38、39、40
只有3个属性全部都选定的时候,才能真正确定你买的是哪一件衣服,也才能知道衣服对应的价格、库存等信息。
如果你只选择了其中1或2个属性,剩下未被选择的属性要进行判断,确定哪些属性值可以被选中,哪些不能(因为有些sku组合不存在,或者库存为0,无法购买)
核心问题
- 如何根据全部属性查询对应的价格、库存?
- 如何确定哪些属性值可以被选中,哪些不能?
前者很简单,遍历一遍所有的SKU信息列表就知道了,或者利用Map直接获取就行。后者比较麻烦,需要进行多次匹配。大体思想如下:
- 遍历SKU列表,从中选出包含
已选中属性和属性值
的条目列表containTargetList; - 遍历containTargetList,找出存在其中的
未被选中属性的属性值
- 结合
未被选中属性的全部属性值
和未被选中属性在containTargetList中存在的属性值
,确定未被选中属性
中哪些属性值是不能被选中的。
附录:Python的简易实现版
#!/usr/bin/python
# -*- coding: utf-8 -*-
#################################
## 输入:连续点击事件
## 输出:各个按钮的状态
#################################
# 不同的规格属性
KEYS = {
"size":["38", "39", "40"],
"color":["red", "blue", "green"],
"sex":["man", "woman"],
};
# 不同的规格属性组合对应的 库存和价格
SKUS = {
"39;red;man":{"price":100, "count":10},
"40;red;man":{"price":100, "count":10},
"38;grean;woman":{"price":100, "count":20},
"39;red;woman":{"price":100, "count":30},
"39;blue;man":{"price":100, "count":10},
"40;blue;man":{"price":100, "count":10},
"38;blue;woman":{"price":100, "count":20},
"39;green;woman":{"price":100, "count":30},
}
def processSku(inputData):
## 1. 预处理数据,将规格的属性值变为对象的属性值,便于读取比较
for sku in SKUS:
array = sku.split(";");
SKUS[sku]["size"] = array[0]
SKUS[sku]["color"] = array[1]
SKUS[sku]["sex"] = array[2]
## 2. 找出被选中的属性值列表
inputDataArray = inputData.split(";");
targetedDict = {}
for data in inputDataArray:
if ":" in data:
[key, value] = data.split(":")
targetedDict[key] = value
print "已经选中的属性:" , targetedDict
if(len(targetedDict) == len(KEYS)):
key = "%s;%s;%s" % (targetedDict["size"],targetedDict["color"],targetedDict["sex"])
if key in SKUS:
print "所有属性皆被选中,对应的结果为\n" , key , ":", SKUS[key]
else:
print "所有属性皆被选中,但查无结果\n"
return;
## 3. 找出未被选中的属性值列表
unTargetDict = {}
for key in KEYS:
if key not in targetedDict:
unTargetDict[key] = KEYS[key]
print "未被选中的属性:" , unTargetDict
## 4. 判断未被选中的属性值是否能被选中
### 4.1. 遍历规格属性组合,找到包含`targetedDict属性值`的所有sku组合
containTargetList = []
for skuItem in SKUS:
canAppend = True
for key in targetedDict:
if SKUS[skuItem][key] != targetedDict[key]:
canAppend = False
break;
if canAppend:
containTargetList.append(SKUS[skuItem])
print "包含选中属性的sku条目:"
for skuItem in containTargetList:
print skuItem
### 4.2 判断每个属性下面每个属性值的存在状态,True表示可以选中,False表示不能继续选择了
skuStaus = {}
for skuKey in unTargetDict:
skuStaus[skuKey] = {}
for skuValue in unTargetDict[skuKey]:
skuStaus[skuKey][skuValue] = False;
for skuItem in containTargetList:
for skuKey in unTargetDict:
for skuValue in unTargetDict[skuKey]:
if skuItem[skuKey] == skuValue:
skuStaus[skuKey][skuValue] = True;
break;
print "\n可继续选中的属性值状态为: "
for skuKey in skuStaus:
print skuKey,":",skuStaus[skuKey]
### 测试数据
inputDatas =[
# "size:39",
"size:40;",
# "size:39;sex:woman", #选中size 39和sex:woman
# "size:39;sex:woman;color:red",
# "size:39;sex:woman;color:red1",
]
for inputData in inputDatas:
print "\n\n------Start:测试数据为%s------" % inputData
processSku(inputData)
print "------end----------------\n\n"
优化建议:
- 如果用户下一次选中的属性值,没有影响之前的属性值选择。也就是说,用户上一次选中了“男”这个属性值,这一次选中了“40”这个属性值,可以直接在上一次containTargetList的基础上继续过滤,而不用遍历全部的SKU列表。
Panda
2016-05-19
参考:
- Fan同学提供的算法概要
- 淘宝SKU组合查询算法实现