前言
最近项目开发涉及商品SKU,商品SKU计算原理就是笛卡尔积,下面对相关内容做一下总结。
一、什么是SKU
SKU=Stock Keeping Unit(库存量单位),即库存进出计量的单位,可以是以件,盒,托盘等为单位。针对电商而言,一款商品SKU主要由商品规格组合,后面会举例子说明。
二、什么是笛卡尔积
笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 。
假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
这里针对商品举例说明,假设衣服由2个规格组成:颜色(黑色、白色)、尺寸(S、M、L),则根据SKU定义和笛卡尔积原理,生成SKU如下:
{('黑色', 'S'), ('黑色', 'M'), ('黑色', 'M'), ('白色', 'S'), ('白色', 'M'), ('白色', 'L')}
三、代码实现
通过上面介绍,我们简单SKU和笛卡尔积,我们知道2个集合怎么生成SKU,但如果3个集合,怎么使用笛卡尔积实现SKU呢。这里我们可以采用分治的方案。就是先把两个集合生成SKU,作为一个集合,再和下一个集合进行笛卡尔积,这样就可以实现三个集合及以上问题。
1.第一方案
type GoodsSpec struct {
Id int64 `json:"id"`
Name string `json:"name"`
}
func main() {
// 颜色
colorSpec := []GoodsSpec{
{
Id: 1,
Name: "白色",
},
{
Id: 2,
Name: "黑色",
},
}
// 尺寸
sizeSpec := []GoodsSpec{
{
Id: 3,
Name: "S",
},
{
Id: 4,
Name: "M",
},
{
Id: 5,
Name: "L",
},
}
// 产地
fieldSpec := []GoodsSpec{
{
Id: 9,
Name: "杭州",
},
{
Id: 10,
Name: "北京",
},
}
skus := GenerateSku(colorSpec, sizeSpec, fieldSpec)
for _, sku := range skus {
log.Printf("%+v", sku)
}
}
func GenerateSku(specs ...[]GoodsSpec) [][]GoodsSpec {
skus := make([][]GoodsSpec, 0)
for _, spec := range specs[0] {
skus = append(skus, []GoodsSpec{spec})
}
for i := 0; i < len(specs)-1; i++ {
skuTemp := make([][]GoodsSpec, 0)
for _, sku := range skus {
for _, spec := range specs[i+1] {
temp := make([]GoodsSpec, 0)
temp = append(temp, sku...)
temp = append(temp, spec)
skuTemp = append(skuTemp, temp)
}
}
skus = skuTemp
}
return skus
}
运行结果:
2.第二方案
type GoodsSpec struct {
Id int64 `json:"id"`
Name string `json:"name"`
}
func main() {
// 颜色
colorSpec := []GoodsSpec{
{
Id: 1,
Name: "白色",
},
{
Id: 2,
Name: "黑色",
},
}
// 尺寸
sizeSpec := []GoodsSpec{
{
Id: 3,
Name: "S",
},
{
Id: 4,
Name: "M",
},
{
Id: 5,
Name: "L",
},
}
// 产地
fieldSpec := []GoodsSpec{
{
Id: 6,
Name: "杭州",
},
{
Id: 7,
Name: "北京",
},
}
sets := GenerateSku(colorSpec, sizeSpec, fieldSpec)
for _, set := range sets {
fmt.Printf("%+v\n", set)
}
}
func GenerateSku(specs ...[]GoodsSpec) [][]GoodsSpec {
lens := func(i int) int {
log.Printf("%+v", i)
return len(specs[i])
}
var skus [][]GoodsSpec
for ix := make([]int, len(specs)); ix[0] < lens(0); nextIndex(ix, lens) {
var r []GoodsSpec
for j, k := range ix {
r = append(r, specs[j][k])
}
skus = append(skus, r)
}
return skus
}
func nextIndex(ix []int, lens func(i int) int) {
for j := len(ix) - 1; j >= 0; j-- {
ix[j]++
if j == 0 || ix[j] < lens(j) {
return
}
ix[j] = 0
}
}
运行结果:
总结
1.先计算第一个集合和第二个集合的笛卡尔积,把结果保存为一个新集合。
2.然后再用新集合与下一个集合计算笛卡尔积,依此循环直到与最后一个集合计算笛卡尔积。