[23→100]SKU组合查询算法

问题场景

SKU最小存货单位(Stock Keeping Unit)在连锁零售门店中有时称单品为一个SKU,定义为保存库存控制的最小可用单位,例如纺织品中一个SKU通常表示规格、颜色、款式。

逛过淘宝的人都知道一种商品可能有多种属性类型,拿一件衣服来说,

  • 性别:男、女
  • 颜色:红、绿、蓝
  • 尺寸上:38、39、40
  1. 只有3个属性全部都选定的时候,才能真正确定你买的是哪一件衣服,也才能知道衣服对应的价格、库存等信息。

  2. 如果你只选择了其中1或2个属性,剩下未被选择的属性要进行判断,确定哪些属性值可以被选中,哪些不能(因为有些sku组合不存在,或者库存为0,无法购买)

核心问题

  1. 如何根据全部属性查询对应的价格、库存?
  2. 如何确定哪些属性值可以被选中,哪些不能?

前者很简单,遍历一遍所有的SKU信息列表就知道了,或者利用Map直接获取就行。后者比较麻烦,需要进行多次匹配。大体思想如下:

  1. 遍历SKU列表,从中选出包含已选中属性和属性值的条目列表containTargetList;
  2. 遍历containTargetList,找出存在其中的未被选中属性的属性值
  3. 结合未被选中属性的全部属性值未被选中属性在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"

优化建议:

  1. 如果用户下一次选中的属性值,没有影响之前的属性值选择。也就是说,用户上一次选中了“男”这个属性值,这一次选中了“40”这个属性值,可以直接在上一次containTargetList的基础上继续过滤,而不用遍历全部的SKU列表。

Panda

2016-05-19

参考:

  1. Fan同学提供的算法概要
  2. 淘宝SKU组合查询算法实现

你可能感兴趣的:([23→100]SKU组合查询算法)