入参依次分别为: List<BoxInfo> boxInfoList,耗材集合 List<GoodsInfo> goodsInfoList,商品集合 Long timeout_per_trail,时间限制(暂时未用) Integer maxTrail,最大线程(暂时未用) Boolean isXiangZhuang,是否箱装 int buffer_auto_bag,自动打包时的袋装buffer double Threshold_box,箱装自动打包优先阈值 double Threshold_bag,袋装自动打包优先阈值 int num_sup,一个袋子最多可拓展的类型数 int buffer,耗材buffer
- 极端情况处理(商品集合为空或者耗材集合为空)
- 耗材集合优先级排序(箱子按体积从小到大,袋子按面积从小到大)
- 将自动打包耗材和手工打包耗材分开
- 手工打包耗材数据预处理(调整至长>=宽>=高)
- 商品数据预处理(调整至长>=宽>=高)
- 把商品分流,分为4类(硬塞的、常规、异形、原包)
- 原包异形包裹计算
- 常规商品集合优先级排序(最长边从小到大)
- 将自动打包商品和手工打包商品分开
- 若满足自动打包则走自动打包逻辑
- 常规计算逻辑
- 无商品时直接返回
- 若均为类缠绕膜耗材,则直接把所有商品打成一个包裹,耗材若唯一则推荐此耗材,若不唯一则不推荐
- 若全部都为硬塞的商品则这些商品走常规推荐
- 根据商品集合的特征分别走不通的算法模块
- 商品数为1时,精确计算
- 商品数为2时,精确计算
- 商品数>=3时
- 若箱装、品类唯一,五块逻辑
- 袋子集扩充为箱子集
- 常规启发式逻辑
- 若存在硬塞的商品,则把其放入第一个包裹里,若无包裹则单独成一个包裹
算法架构流程
public static List<Package> getPackagePair(List<BoxInfo> boxInfoList, List<GoodsInfo> goodsInfoList,
Long timeout_per_trail, Integer maxTrail, Boolean isXiangZhuang,
int buffer_auto_bag, double Threshold_box, double Threshold_bag, int num_sup, int buffer)
throws Exception {
//极端情况(耗材集合为0或者商品集合为0)处理
if(goodsInfoList.size() == 0){
return new ArrayList<Package>();
}else if(boxInfoList.size() == 0){
List<Package> resPackageList = new ArrayList<Package>();
Package temp_package = new Package();
for (int i = 0; i < goodsInfoList.size(); i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList.get(i)));
}
resPackageList.add(temp_package);
return resPackageList;
}
//根据手工耗材类型对体积或面积进行排序,从小到大排
if (isXiangZhuang) {
V_box_sorting(boxInfoList);
} else {
S_box_sorting(boxInfoList);
}
//将自动打包耗材和手工打包耗材分开
List<BoxInfo> boxInfoList_auto = new ArrayList<BoxInfo>();
List<BoxInfo> boxInfoList_normal = new ArrayList<BoxInfo>();
for (BoxInfo boxInfo : boxInfoList) {
if (boxInfo.auto == 1) {
boxInfoList_auto.add(boxInfo);
} else {
boxInfoList_normal.add(boxInfo);
}
}
//手工打包耗材数据预处理
//默认包装装时长大于等于宽大于等于高
for (BoxInfo boxInfo : boxInfoList_normal) {
int length = Math.max(boxInfo.Length, Math.max(boxInfo.Width, boxInfo.Height));
int height = Math.min(boxInfo.Length, Math.min(boxInfo.Width, boxInfo.Height));
int width = boxInfo.Length + boxInfo.Width + boxInfo.Height - length - height;
boxInfo.Length = length;
boxInfo.Width = width;
boxInfo.Height = height;
}
//商品货物数据预处理
//对货物尺寸排序,长大于等于宽大于等于高
for (GoodsInfo goodsInfo : goodsInfoList) {
double length = Math.max(goodsInfo.Length, Math.max(goodsInfo.Width, goodsInfo.Height));
double height = Math.min(goodsInfo.Length, Math.min(goodsInfo.Width, goodsInfo.Height));
double width = goodsInfo.Length + goodsInfo.Width + goodsInfo.Height - length - height;
goodsInfo.Length = length;
goodsInfo.Width = width;
goodsInfo.Height = height;
}
//不考虑装载,直接硬塞的商品,放在第一个包裹里
List<GoodsInfo> goodsInfoList0 = new ArrayList<GoodsInfo>();
//根据flag筛选分流商品,1常规,2异形,3原包
List<GoodsInfo> goodsInfoList1 = new ArrayList<GoodsInfo>();
List<GoodsInfo> goodsInfoList2 = new ArrayList<GoodsInfo>();
List<GoodsInfo> goodsInfoList3 = new ArrayList<GoodsInfo>();
for (GoodsInfo goodsInfo : goodsInfoList) {
if (goodsInfo.Length <= 10 || goodsInfo.Width <= 10 || goodsInfo.Height <= 10) {
goodsInfoList0.add(new GoodsInfo(goodsInfo));
continue;
}
if (goodsInfo.flag == 1) {
//确定每一个商品在这组耗材下能够装下,装不下的当做异形处理
if (suitable(boxInfoList_auto, boxInfoList_normal, goodsInfo, isXiangZhuang, buffer)) {
goodsInfoList1.add(new GoodsInfo(goodsInfo));
} else {
goodsInfoList2.add(new GoodsInfo(goodsInfo));
}
} else if (goodsInfo.flag == 2) {
goodsInfoList2.add(new GoodsInfo(goodsInfo));
} else {
goodsInfoList3.add(new GoodsInfo(goodsInfo));
}
}
//异形、原包包裹计算
List<Package> resPackageList_alien = Alien.alien(goodsInfoList2);
List<Package> resPackageList_original = Original.original(goodsInfoList3);
//初始化结果Package的List并把原包异形结果加入
List<Package> resPackageList = new ArrayList<Package>();
resPackageList.addAll(resPackageList_alien);
resPackageList.addAll(resPackageList_original);
//常规商品集GoodsInfoList1装载
//对商品最长边进行排序,长的放前面,先装
goods_edge_sorting(goodsInfoList1);
List<GoodsInfo> goodsInfoList1_auto = new ArrayList<GoodsInfo>();
List<GoodsInfo> goodsInfoList1_normal = new ArrayList<GoodsInfo>();
for (GoodsInfo goodsInfo : goodsInfoList1) {
if (goodsInfo.auto == 1) {
goodsInfoList1_auto.add(new GoodsInfo(goodsInfo));
} else {
goodsInfoList1_normal.add(new GoodsInfo(goodsInfo));
}
}
//优先看是否满足自动打包约束
if (goodsInfoList1_auto.size() == 1 && goodsInfoList1_normal.size() == 0) {
StackingAuto.auto(boxInfoList_auto, boxInfoList_normal, goodsInfoList1_auto, isXiangZhuang, resPackageList, buffer, buffer_auto_bag, Threshold_box, Threshold_bag);
packageSummary(resPackageList);
return resPackageList;
}
//其他情况走常规手工打包逻辑
//无商品时直接返回
if(goodsInfoList0.size() == 0 && goodsInfoList1.size() == 0){
packageSummary(resPackageList);
return resPackageList;
}
//手工打包前,检查耗材是否均为类缠绕膜耗材
if(ismembrane(boxInfoList_normal)){
Package temp_package = new Package();
if (boxInfoList_normal.size() == 1){
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(0)));
}
for (int i = 0; i < goodsInfoList0.size(); i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList0.get(i)));
}
for (int i = 0; i < goodsInfoList1.size(); i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(i)));
}
resPackageList.add(temp_package);
return resPackageList;
}
if(goodsInfoList1.size() == 0){
for (int i = 0; i < goodsInfoList0.size(); i++) {
goodsInfoList1.add(new GoodsInfo(goodsInfoList0.get(i)));
}
goodsInfoList0 = new ArrayList<GoodsInfo>();
}
//至此,isXiangZhuang决定知否箱装,boxInfoList_normal和bagList分别为箱装耗材和袋装耗材集合,GoodsInfoList1是待装商品集
//resPackageList为异形原包形成的包裹集,清洗好了数据,开始分情况装载
//1个和2个基本属于精确求解,3个以上启发式求解
//3个以上如果商品类型唯一的话触发5块逻辑
//剩下的情形是size大于等于3的情况,此时走以下常规流程
Set<String> skuSet = new HashSet<String>();
for (GoodsInfo goodsInfo : goodsInfoList1) {
skuSet.add(goodsInfo.sku);
}
if (goodsInfoList1.size() == 1) {
StackingSimple.size_1(boxInfoList_normal, goodsInfoList1, isXiangZhuang, resPackageList, buffer);
} else if (goodsInfoList1.size() == 2) {
StackingSimple.size_2(boxInfoList_normal, goodsInfoList1, isXiangZhuang, resPackageList, buffer);
} else if (goodsInfoList1.size() >= 3 && isXiangZhuang && skuSet.size() == 1) {
StackingSimple.one_sku_size_more(boxInfoList_normal, goodsInfoList1, resPackageList, buffer);
} else if (goodsInfoList1.size() >= 3) {
List<BoxInfo> bagList_normal = createBagList(boxInfoList_normal, num_sup);
StackingHeuristic.size_more(boxInfoList_normal, bagList_normal, goodsInfoList1, isXiangZhuang, resPackageList, buffer);
}
//看是否存在礼品袋
if(goodsInfoList0.size() > 0){
//如果存在包裹,则把硬塞的商品放在第一个包裹里,否则新建包裹
if (resPackageList.size() > 0) {
for (int i = 0; i < goodsInfoList0.size(); i++) {
resPackageList.get(0).getGoods().add(new GoodsInfo(goodsInfoList0.get(i)));
}
} else {
Package temp_package = new Package();
if (boxInfoList_normal.size() == 1){
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(0)));
}
for (int i = 0; i < goodsInfoList0.size(); i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList0.get(i)));
}
resPackageList.add(temp_package);
}
}
packageSummary(resPackageList);
return resPackageList;
}
附1、耗材排序模块
static void V_box_sorting(List<BoxInfo> boxInfoList) {
Collections.sort(boxInfoList, new Comparator<BoxInfo>() {
@Override
//-1优先,体积小的放前面
public int compare(BoxInfo b1, BoxInfo b2) {
int v1 = b1.Length*b1.Width*b1.Height;
int v2 = b2.Length*b2.Width*b2.Height;
if(v1 < v2) {
return -1;
} else{
return 1;
}
}
});
}
static void S_box_sorting(List<BoxInfo> boxInfoList) {
Collections.sort(boxInfoList, new Comparator<BoxInfo>() {
@Override
//-1优先,面积小的放前面,面积相等时,长边小的放前面,再相等时看高
public int compare(BoxInfo b1, BoxInfo b2) {
int l1 = Math.max(b1.Length,Math.max(b1.Width,b1.Height));
int h1 = Math.min(b1.Length,Math.min(b1.Width,b1.Height));
int w1 = b1.Length+b1.Width+b1.Height-l1-h1;
int l2 = Math.max(b2.Length,Math.max(b2.Width,b2.Height));
int h2 = Math.min(b2.Length,Math.min(b2.Width,b2.Height));
int w2 = b2.Length+b2.Width+b2.Height-l2-h2;
if(l1*w1 < l2*w2) {
return -1;
}else if(l1*w1 > l2*w2){
return 1;
}else if(l1 < l2) {
return -1;
}else if(l1 > l2){
return 1;
}else if(h1 < h2){
return -1;
}else{
return 1;
}
}
});
}
附2、常规商品在这组耗材下是否能装下(否的话作为异形处理)
static Boolean suitable(List<BoxInfo> boxInfoList_auto, List<BoxInfo>boxInfoList_normal, GoodsInfo goodsInfo, Boolean isXiangZhuang, int buffer){
Boolean code = false;
if(goodsInfo.auto == 0){
if(isXiangZhuang){
for(BoxInfo b:boxInfoList_normal){
if(b.Length+buffer>=goodsInfo.Length && b.Width+buffer>=goodsInfo.Width && b.Height+buffer>=goodsInfo.Height){
code = true;
break;
}
}
}else{
for(BoxInfo b:boxInfoList_normal){
if(b.Length+b.Height-goodsInfo.Height+buffer>=goodsInfo.Length && b.Width+b.Height-goodsInfo.Height+buffer>=goodsInfo.Width){
code = true;
break;
}
}
}
}else{
//自动包装时,不考虑buffer,在自动包装装不下时,考虑手动打包
if(isXiangZhuang){
for(BoxInfo b:boxInfoList_auto){
int length = Math.max(b.Length,Math.max(b.Width,b.Height));
int height = Math.min(b.Length,Math.min(b.Width,b.Height));
int width = b.Length+b.Width+b.Height-length-height;
if(length>=goodsInfo.Length && width>=goodsInfo.Width && height>=goodsInfo.Height){
code = true;
break;
}
}
if(!code){
for(BoxInfo b:boxInfoList_normal){
if(b.Length+buffer>=goodsInfo.Length && b.Width+buffer>=goodsInfo.Width && b.Height+buffer>=goodsInfo.Height){
code = true;
break;
}
}
}
}else{
for(BoxInfo b:boxInfoList_auto){
int length = Math.max(b.Length,Math.max(b.Width,b.Height));
int height = Math.min(b.Length,Math.min(b.Width,b.Height));
int width = b.Length+b.Width+b.Height-length-height;
if(length+height-goodsInfo.Height>=goodsInfo.Length && width+height-goodsInfo.Height>=goodsInfo.Width){
code = true;
break;
}
}
if(!code){
for(BoxInfo b:boxInfoList_normal){
if(b.Length+b.Height-goodsInfo.Height+buffer>=goodsInfo.Length && b.Width+b.Height-goodsInfo.Height+buffer>=goodsInfo.Width){
code = true;
break;
}
}
}
}
}
return code;
}
附3、异形计算模块
package com.jd.jingwei.algorithm.method_alien;
import com.jd.jingwei.basis.*;
import com.jd.jingwei.basis.Package;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Alien {
static void goods_coefficient_package_sorting(List<GoodsInfo> goodsInfoList) {
Collections.sort(goodsInfoList, new Comparator<GoodsInfo>() {
@Override
//-1优先,最长边大的放前面
public int compare(GoodsInfo g1, GoodsInfo g2) {
double c1 = g1.coefficient_package;
double c2 = g2.coefficient_package;
if(c1 > c2) {
return -1;
} else{
return 1;
}
}
});
}
//判断是否存在没有形成包裹的商品
static Integer num_exist(List<Integer>Goods_used_state){
Integer sum_state = 0;
for(Integer i:Goods_used_state){
sum_state += i;
}
return sum_state;
}
//把异形包裹里,每个包裹里商品的包裹系数打印出来
public static void VCS(List<Package> resPackageList_alien){
for(Package p:resPackageList_alien){
System.out.print("[");
for(GoodsInfo goodsInfo:p.getGoods()){
System.out.print(goodsInfo.coefficient_package+" , ");
}
System.out.println("]");
}
}
public static List<Package> alien(List<GoodsInfo> GoodsInfoList2){
List<Package> resPackageList_alien = new ArrayList<Package>();
//按包裹系数排序,大的放前面
goods_coefficient_package_sorting(GoodsInfoList2);
//Goods_used_state表示每个Good的使用状态
List<Integer> Goods_used_state = new ArrayList<Integer>();
for(GoodsInfo g:GoodsInfoList2){
Goods_used_state.add(1);
}
//先把大于等于1的处理了
for(int i = 0; i < GoodsInfoList2.size(); i++){
if(GoodsInfoList2.get(i).coefficient_package >= 1){
Package temp_package = new Package();
temp_package.getGoods().add(new GoodsInfo(GoodsInfoList2.get(i)));
Goods_used_state.set(i,0);
resPackageList_alien.add(temp_package);
}
}
while(num_exist(Goods_used_state) > 0){
Package temp_package = new Package();
double sum_coefficient = 0;
for (int i = 0; i < GoodsInfoList2.size(); i++) {
if(Goods_used_state.get(i) > 0 && sum_coefficient + GoodsInfoList2.get(i).coefficient_package <= 1){
temp_package.getGoods().add(new GoodsInfo(GoodsInfoList2.get(i)));
Goods_used_state.set(i,0);
sum_coefficient += GoodsInfoList2.get(i).coefficient_package;
}
}
resPackageList_alien.add(temp_package);
}
VCS(resPackageList_alien);
return resPackageList_alien;
}
}
附4、原包计算逻辑
public static List<Package> original(List<GoodsInfo> GoodsInfoList3) {
List<Package> resPackageList_original = new ArrayList<Package>();
HashMap<GoodsInfo, Integer> nums_sku = new HashMap<GoodsInfo, Integer>();
for(GoodsInfo goodsInfo:GoodsInfoList3){
if (nums_sku.get(goodsInfo) == null) {
nums_sku.put(goodsInfo, 1);
} else {
nums_sku.put(goodsInfo, nums_sku.get(goodsInfo)+1);
}
}
for(Map.Entry<GoodsInfo, Integer> entry: nums_sku.entrySet()){
if(entry.getKey().coefficient_package <= 0){
Package temp_package = new Package();
for (int i = 0; i < entry.getValue(); i++) {
temp_package.getGoods().add(new GoodsInfo(entry.getKey()));
}
resPackageList_original.add(temp_package);
}else{
for (int i = 0; i < entry.getValue()*entry.getKey().coefficient_package; i++) {
Package temp_package = new Package();
for (int j = 0; j < 1.0/entry.getKey().coefficient_package; j++) {
temp_package.getGoods().add(new GoodsInfo(entry.getKey()));
}
resPackageList_original.add(temp_package);
}
Package temp_package = new Package();
for (int j = 0; j < 1.0/entry.getKey().coefficient_package; j++) {
temp_package.getGoods().add(new GoodsInfo(entry.getKey()));
}
resPackageList_original.add(temp_package);
}
}
for(int i = 0; i < GoodsInfoList3.size(); i++){
Package temp_package = new Package();
temp_package.getGoods().add(new GoodsInfo(GoodsInfoList3.get(i)));
resPackageList_original.add(temp_package);
}
Alien.VCS(resPackageList_original);
return resPackageList_original;
}
附5、商品优先级排序
static void goods_edge_sorting(List<GoodsInfo> goodsInfoList) {
Collections.sort(goodsInfoList, new Comparator<GoodsInfo>() {
@Override
//-1优先,最长边大的放前面
public int compare(GoodsInfo g1, GoodsInfo g2) {
double l1 = g1.Length;
double l2 = g2.Length;
if(l1 > l2) {
return -1;
} else{
return 1;
}
}
});
}
附6、自动打包逻辑
package com.jd.jingwei.algorithm.method_normal;
import com.jd.jingwei.basis.BoxInfo;
import com.jd.jingwei.basis.GoodsInfo;
import com.jd.jingwei.basis.Package;
import java.util.ArrayList;
import java.util.List;
public class StackingAuto {
public static void auto(List<BoxInfo> boxInfoList_auto, List<BoxInfo> boxInfoList_normal, List<GoodsInfo> goodsInfoList1_auto,
Boolean isXiangZhuang, List<Package> resPackageList, int buffer, int buffer_auto_bag, double Threshold_box, double Threshold_bag){
//自动包装时,不考虑buffer,在自动包装装不下时,考虑手动打包
//目前只考虑单品的自动打包
GoodsInfo goodsInfo = goodsInfoList1_auto.get(0);
if(isXiangZhuang){
int idex_auto = -1;
int V_auto = 0;
int idex_normal = -1;
int V_normal = 0;
for(int i=0; i<boxInfoList_auto.size(); i++){
int length = Math.max(boxInfoList_auto.get(i).Length,Math.max(boxInfoList_auto.get(i).Width,boxInfoList_auto.get(i).Height));
int height = Math.min(boxInfoList_auto.get(i).Length,Math.min(boxInfoList_auto.get(i).Width,boxInfoList_auto.get(i).Height));
int width = boxInfoList_auto.get(i).Length+boxInfoList_auto.get(i).Width+boxInfoList_auto.get(i).Height-length-height;
if(length>=goodsInfo.Length && width>=goodsInfo.Width && height>=goodsInfo.Height){
idex_auto = i;
V_auto = boxInfoList_auto.get(i).Volume;
break;
}
}
for(int i=0; i<boxInfoList_normal.size(); i++){
int length = Math.max(boxInfoList_normal.get(i).Length,Math.max(boxInfoList_normal.get(i).Width,boxInfoList_normal.get(i).Height));
int height = Math.min(boxInfoList_normal.get(i).Length,Math.min(boxInfoList_normal.get(i).Width,boxInfoList_normal.get(i).Height));
int width = boxInfoList_normal.get(i).Length+boxInfoList_normal.get(i).Width+boxInfoList_normal.get(i).Height-length-height;
if(length+buffer>=goodsInfo.Length && width+buffer>=goodsInfo.Width && height+buffer>=goodsInfo.Height){
idex_normal = i;
V_normal = boxInfoList_normal.get(i).Volume;
break;
}
}
Package temp_package = new Package();
if(idex_auto != -1 && idex_normal != -1){
if(goodsInfo.Volume*V_normal >= goodsInfo.Volume*V_auto-Threshold_box*V_normal*V_auto){
temp_package.setBox(new BoxInfo(boxInfoList_auto.get(idex_auto)));
}else {
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(idex_normal)));
}
}else if(idex_auto != -1){
temp_package.setBox(new BoxInfo(boxInfoList_auto.get(idex_auto)));
}else if(idex_normal != -1){
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(idex_normal)));
}
temp_package.getGoods().add(new GoodsInfo(goodsInfo));
resPackageList.add(temp_package);
}else{
boolean code_auto = false;
List<Double> L_V = new ArrayList<Double>();
for(BoxInfo b:boxInfoList_auto){
int length = Math.max(b.Length,b.Height);
int height = Math.min(b.Length,b.Height);
int width = b.Width;
if(goodsInfo.Length <= width && goodsInfo.Width <= length && goodsInfo.Height <= height){
code_auto = true;
L_V.add((goodsInfo.Width+buffer_auto_bag)*goodsInfo.Height*width);
continue;
}
if(goodsInfo.Width <= width && goodsInfo.Length <= length && goodsInfo.Height <= height){
code_auto = true;
L_V.add((goodsInfo.Length+buffer_auto_bag)*goodsInfo.Height*width);
continue;
}
if(goodsInfo.Height <= width && goodsInfo.Length <= length && goodsInfo.Width <= height){
code_auto = true;
L_V.add((goodsInfo.Length+buffer_auto_bag)*goodsInfo.Width*width);
continue;
}
L_V.add(Double.MAX_VALUE);
}
boolean code_normal = false;
int idex_normal = -1;
double V_normal = Double.MAX_VALUE;
for(int i=0; i<boxInfoList_normal.size(); i++){
BoxInfo b = boxInfoList_normal.get(i);
if(b.Length+b.Height-goodsInfo.Height+buffer >= goodsInfo.Length &&
b.Width+b.Height-goodsInfo.Height+buffer >= goodsInfo.Width){
code_normal = true;
idex_normal = i;
V_normal = (b.Length+b.Height-goodsInfo.Height)*(b.Width+b.Height-goodsInfo.Height)*goodsInfo.Height;
break;
}
}
Package temp_package = new Package();
if(code_auto) {
int idex_auto = 0;
for(int i=1; i<L_V.size(); i++){
if(L_V.get(idex_auto) > L_V.get(i)){
idex_auto = i;
}
}
if(code_normal){
if(goodsInfo.Volume*V_normal >= goodsInfo.Volume*L_V.get(idex_auto)-Threshold_bag*V_normal*L_V.get(idex_auto)){
temp_package.setBox(new BoxInfo(boxInfoList_auto.get(idex_auto)));
}else {
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(idex_normal)));
}
}else{
temp_package.setBox(new BoxInfo(boxInfoList_auto.get(idex_auto)));
}
}else if(code_normal){
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(idex_normal)));
}
temp_package.getGoods().add(new GoodsInfo(goodsInfo));
resPackageList.add(temp_package);
}
}
}
附7、检查是否均为类缠绕膜耗材
static Boolean ismembrane(List<BoxInfo> boxInfoList){
Boolean flag = true;
for(BoxInfo b: boxInfoList){
if(b.Length > 10 || b.Width > 10 || b.Height > 10){
flag = false;
break;
}
}
return flag;
}
主1、商品数为1时
public static void size_1(List<BoxInfo> boxInfoList_normal, List<GoodsInfo> goodsInfoList1,
Boolean isXiangZhuang, List<Package> resPackageList, int buffer){
//由于boxInfoList_normal是按照损耗排过序的,因此遇到合适能装下的就装,然后break
if(isXiangZhuang){
for(BoxInfo boxInfo: boxInfoList_normal){
if(boxInfo.Length+buffer >= goodsInfoList1.get(0).Length &&
boxInfo.Width+buffer >= goodsInfoList1.get(0).Width &&
boxInfo.Height+buffer >= goodsInfoList1.get(0).Height){
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(boxInfo));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
resPackageList.add(temp_package);
break;
}
}
}else{
for(BoxInfo boxInfo: boxInfoList_normal){
if(boxInfo.Length+boxInfo.Height-goodsInfoList1.get(0).Height+buffer >= goodsInfoList1.get(0).Length &&
boxInfo.Width+boxInfo.Height-goodsInfoList1.get(0).Height+buffer >= goodsInfoList1.get(0).Width){
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(boxInfo.Length+boxInfo.Height-goodsInfoList1.get(0).Height.intValue(),
boxInfo.Width+boxInfo.Height-goodsInfoList1.get(0).Height.intValue(),
goodsInfoList1.get(0).Height.intValue(),
boxInfo.name,
boxInfo.weight, 0));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
resPackageList.add(temp_package);
break;
}
}
}
}
主2、商品数为2时
public static void size_2(List<BoxInfo> boxInfoList_normal, List<GoodsInfo> goodsInfoList1,
Boolean isXiangZhuang,List<Package> resPackageList, int buffer){
int code = 0;
//先尝试放一个耗材里,两个商品组合成为一个更大的商品尺寸
List<GoodsInfo> Double_Goods = new ArrayList<GoodsInfo>();
double l1 = goodsInfoList1.get(0).Length;
double w1 = goodsInfoList1.get(0).Width;
double h1 = goodsInfoList1.get(0).Height;
double l2 = goodsInfoList1.get(1).Length;
double w2 = goodsInfoList1.get(1).Width;
double h2 = goodsInfoList1.get(1).Height;
Double_Goods.add(new GoodsInfo(l1+l2, Math.max(w1,w2),Math.max(h1,h2), "1", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(l1+w2, Math.max(w1,l2),Math.max(h1,h2), "2", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(l1+h2, Math.max(w1,l2),Math.max(h1,w2), "3", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(w1+l2, Math.max(l1,w2),Math.max(h1,h2), "4", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(w1+w2, Math.max(l1,l2),Math.max(h1,h2), "5", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(w1+h2, Math.max(l1,l2),Math.max(h1,w2), "6", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(h1+l2, Math.max(l1,w2),Math.max(w1,h2), "7", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(h1+w2, Math.max(l1,l2),Math.max(w1,h2), "8", 1, 1d, 0,1));
Double_Goods.add(new GoodsInfo(h1+h2, Math.max(l1,l2),Math.max(w1,w2), "9", 1, 1d, 0,1));
//保证更大尺寸的商品长大于等于宽大于等于高
for(GoodsInfo goodsInfo: Double_Goods){
double length = Math.max(goodsInfo.Length,Math.max(goodsInfo.Width,goodsInfo.Height));
double height = Math.min(goodsInfo.Length,Math.min(goodsInfo.Width,goodsInfo.Height));
double width = goodsInfo.Length+goodsInfo.Width+goodsInfo.Height-length-height;
goodsInfo.Length = length;
goodsInfo.Width = width;
goodsInfo.Height = height;
}
//至此,耗材集合为L(L中长大于等于宽大于等于高,且最长边逐渐变长)
// 商品可能尺寸集合为Double_Goods,尝试装载,其中一个可以装下即说明可以用单个耗材装下
if(isXiangZhuang){
for(BoxInfo b:boxInfoList_normal){
for(GoodsInfo g:Double_Goods){
if(b.Length+buffer >= g.Length && b.Width+buffer >= g.Width && b.Height+buffer >= g.Height){
code = 1;
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(b));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(1)));
resPackageList.add(temp_package);
break;
}
}
if(code == 1){
break;
}
}
}else{
for(BoxInfo b:boxInfoList_normal){
for(GoodsInfo g:Double_Goods){
if(b.Length+b.Height-g.Height+buffer >= g.Length && b.Width+b.Height-g.Height+buffer >= g.Width){
code = 1;
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(b.Length+b.Height-g.Height.intValue(),
b.Width+b.Height-g.Height.intValue(),
g.Height.intValue(),
b.name,
b.weight, 0));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(1)));
resPackageList.add(temp_package);
break;
}
}
if(code == 1){
break;
}
}
}
//一个箱子装不下,分开试装
if(code == 0){
List<GoodsInfo> L1 = new ArrayList<GoodsInfo>();
List<GoodsInfo> L2 = new ArrayList<GoodsInfo>();
L1.add(goodsInfoList1.get(0));
L2.add(goodsInfoList1.get(1));
size_1(boxInfoList_normal,L1,isXiangZhuang,resPackageList,buffer);
size_1(boxInfoList_normal,L2,isXiangZhuang,resPackageList,buffer);
}
}
主3、商品数>=3、箱装、品类唯一
static int one_sku_put(double CL, double CW, double CH, double l, double w, double h){
//简单码放模式,确定码放下界
int maxnum = ((int)(CL/l)*(int)(CW/w) + (int)((CL-(int)(CL/l)*l)/w)*(int)(CW/l))*(int)(CH/h);
int newone = ((int)(CW/l)*(int)(CL/w) + (int)((CW-(int)(CW/l)*l)/w)*(int)(CL/l))*(int)(CH/h);
maxnum=maxnum>=newone?maxnum:newone;
//五块调整,当剩余面积大于一块底面积时触发
if((int)(CL*CW/l/w)*(int)(CH/h) > maxnum & CW >= l+w) {
int x1,x2,x3,x4,y1,y2,y3,y4;
int up1 = (int)(CL/l), up2 = (int)(CL/w), up3 = (int)(CW/l), up4 = (int)(CW/w);
for(x1=1; x1<=up1; x1++) {
x2 = (int)((CL-x1*l)/w);
for(y1=1; y1<=up4; y1++) {
y4 = (int)((CW-y1*w)/l);
for(y2=1; y2<=up3; y2++) {
y3 = (int)((CW-y2*l)/w);
for(x3=1; x3<=up1; x3++) {
x4 = (int)((CL-x3*l)/w);
if (y1*w <= y2*l && x2*w <= x3*l && y3*w <= y4*l && x4*w <= x1*l) {
if ((y1 + y3) * w > CW || (x2 + x4) * w > CL) {
continue;
}
int n = (x1*y1+x2*y2+x3*y3+x4*y4)*(int)(CH/h);
maxnum=maxnum>=n?maxnum:n;
}
if (y1*w >= y2*l && x2*w >= x3*l && y3*w >= y4*l && x4*w >= x1*l){
if((x1+x3)*l>CL || (y2+y4)*l>CW){
continue;
}
int n = (x1*y1+x2*y2+x3*y3+x4*y4)*(int)(CH/h);
maxnum=maxnum>=n?maxnum:n;
}
}
}
}
}
}
return maxnum;
}
public static void one_sku_size_more(List<BoxInfo> boxInfoList_normal, List<GoodsInfo> goodsInfoList1,
List<Package> resPackageList, int buffer){
double l = goodsInfoList1.get(0).Length;
double w = goodsInfoList1.get(0).Width;
double h = goodsInfoList1.get(0).Height;
int nums_goods = goodsInfoList1.size();
List<Pair<Integer,Integer>> nums_can_put = new ArrayList<Pair<Integer, Integer>>();
int max_loc = 0;
for (int i = 0; i < boxInfoList_normal.size(); i++) {
double CL = boxInfoList_normal.get(i).Length + buffer;
double CW = boxInfoList_normal.get(i).Width + buffer;
double CH = boxInfoList_normal.get(i).Height + buffer;
//筛选,只把那些利用率比较高的存下来
int num1 = one_sku_put(CL, CW, CH, l, w, h);
int num2 = one_sku_put(CL, CH, CW, l, w, h);
int num3 = one_sku_put(CW, CH, CL, l, w, h);
int num4 = one_sku_put(CL, CW, CH, l, h, w);
int num5 = one_sku_put(CL, CH, CW, l, h, w);
int num6 = one_sku_put(CW, CH, CL, l, h, w);
int num7 = one_sku_put(CL, CW, CH, w, h, l);
int num8 = one_sku_put(CL, CH, CW, w, h, l);
int num9 = one_sku_put(CW, CH, CL, w, h, l);
int num = num1;
num = num>=num2?num:num2;
num = num>=num3?num:num3;
num = num>=num4?num:num4;
num = num>=num5?num:num5;
num = num>=num6?num:num6;
num = num>=num7?num:num7;
num = num>=num8?num:num8;
num = num>=num9?num:num9;
if(num > max_loc){
max_loc = num;
nums_can_put.add(new Pair<Integer, Integer>(i,num));
}
}
if(nums_can_put.size() == 0){
return;
}
if(nums_can_put.get(nums_can_put.size()-1).getValue() == 0){
return;
}
int goods_left = nums_goods;
while(goods_left >= nums_can_put.get(nums_can_put.size()-1).getValue()){
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(nums_can_put.get(nums_can_put.size()-1).getKey())));
for (int i = 0; i < nums_can_put.get(nums_can_put.size()-1).getValue(); i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
}
resPackageList.add(temp_package);
goods_left -= nums_can_put.get(nums_can_put.size()-1).getValue();
}
if(goods_left == 0){
return;
}
int idex = nums_can_put.size()-1;
while(idex > 0){
if(nums_can_put.get(idex-1).getValue() >= goods_left){
idex -= 1;
}else{
break;
}
}
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(boxInfoList_normal.get(nums_can_put.get(idex).getKey())));
for (int i = 0; i < goods_left; i++) {
temp_package.getGoods().add(new GoodsInfo(goodsInfoList1.get(0)));
}
resPackageList.add(temp_package);
}
主4、袋子集扩充为箱子集
static List<BoxInfo> createBagList(List<BoxInfo> boxInfoList , int num_sup) {
List<BoxInfo> bagList_normal = new ArrayList<BoxInfo>();
for (BoxInfo boxInfo : boxInfoList) {
//袋子交换宽和高,宽最短,高次短
int length = boxInfo.Length;
int width = boxInfo.Height;
int height = boxInfo.Width;
int step = (length - width) / (2 * num_sup);
if (step % 10 > 0) {
step = step + 10 - step % 10;
}
if (step <= 0) {
bagList_normal.add(new BoxInfo(length, width, height, boxInfo.name, boxInfo.weight, 0));
} else {
while (length >= width && height > 0) {
bagList_normal.add(new BoxInfo(length, width, height, boxInfo.name, boxInfo.weight, 0));
length -= step;
width += step;
height -= step;
}
}
}
for(BoxInfo boxInfo:bagList_normal){
int length = Math.max(boxInfo.Length,Math.max(boxInfo.Width,boxInfo.Height));
int height = Math.min(boxInfo.Length,Math.min(boxInfo.Width,boxInfo.Height));
int width = boxInfo.Length+boxInfo.Width+boxInfo.Height-length-height;
boxInfo.Length = length;
boxInfo.Width = width;
boxInfo.Height = height;
}
return bagList_normal;
}
主5、商品数>=3正常启发式逻辑
package com.jd.jingwei.algorithm.method_normal;
import com.jd.jingwei.basis.BoxInfo;
import com.jd.jingwei.basis.GoodsInfo;
import com.jd.jingwei.basis.Package;
import com.jd.jingwei.tool.*;
import java.util.ArrayList;
import java.util.List;
public class StackingHeuristic {
static Boolean feasible(BoxInfo b, List<GoodsInfo> realGoodsInfoList){
Boolean code = true;
for (GoodsInfo g:realGoodsInfoList){
if(b.Length<g.Length || b.Width<g.Width || b.Height<g.Height){
code = false;
}
}
return code;
}
//对于一类耗材,看最多需要几个耗材装下待装货物,属于装箱问题,这里采用简单版装载
static Pair<BoxInfo,Integer> simplePacking(BoxInfo b, List<GoodsInfo> realGoodsInfoList){
int CL = b.Length;
int CW = b.Width;
int CH = b.Height;
//首先判定每个商品是否都能装下,装不下则直接略过
if(!feasible(b,realGoodsInfoList)){
return new Pair<BoxInfo,Integer>(b,-1);
}
//将商品按照高度CH约束摞成条状,转为二维问题,存在rectangle中
List<List<Double>> rectangle = new ArrayList<List<Double>>();
double length_used = 0;
double width_used = 0;
double height_used = 0;
//Goods_used_state表示每个Good的使用状态
List<Integer> Goods_used_state = new ArrayList<Integer>();
for(GoodsInfo g:realGoodsInfoList){
Goods_used_state.add(1);
}
while(num_exist(Goods_used_state)>0){
length_used = 0;
width_used = 0;
height_used = 0;
for(int i=0; i<Goods_used_state.size(); i++){
if(Goods_used_state.get(i) == 1 && height_used+realGoodsInfoList.get(i).Height <= CH){
height_used += realGoodsInfoList.get(i).Height;
length_used = Math.max(length_used, realGoodsInfoList.get(i).Length);
width_used = Math.max(width_used, realGoodsInfoList.get(i).Width);
Goods_used_state.set(i,0);
}
}
List<Double> temp_L = new ArrayList<Double>();
temp_L.add(length_used);
temp_L.add(width_used);
rectangle.add(temp_L);
}
//摞转成条,用CW去卡,存在length_set中
List<Double> length_set = new ArrayList<Double>();
List<Integer> rec_used_state = new ArrayList<Integer>();
for(int i=0; i<rectangle.size(); i++){
rec_used_state.add(1);
}
double width_used_1 = 0;
double l_bar = 0;
while(num_exist(rec_used_state)>0){
width_used_1 = 0;
l_bar = 0;
for(int i=0; i<rec_used_state.size(); i++){
if(rec_used_state.get(i) == 1 && width_used_1+rectangle.get(i).get(1) <= CW){
width_used_1 += rectangle.get(i).get(1);
l_bar = Math.max(l_bar,rectangle.get(i).get(0));
rec_used_state.set(i,0);
}
}
length_set.add(l_bar);
}
//计算需要多少箱子
List<Double> box_status = new ArrayList<Double>();
box_status.add(0d);
for(Double l:length_set){
int code = 0;
for(int i = 0;i<box_status.size();i++){
if(l+box_status.get(i) <= CL){
box_status.set(i,box_status.get(i)+l);
code = 1;
break;
}
}
if(code == 0){
box_status.add(l);
}
}
return new Pair<BoxInfo,Integer>(b,box_status.size());
}
//判断是否存在没有形成条的箱子
static Integer num_exist(List<Integer>Goods_used_state){
Integer sum_state = 0;
for(Integer i:Goods_used_state){
sum_state += i;
}
return sum_state;
}
static void pushgoods(List<GoodsInfo> L, List<List<GoodsInfo>> res_LL, int idex){
for(GoodsInfo g:L){
res_LL.get(idex).add(new GoodsInfo(g));
}
}
static List<GoodsInfo> breaking(List<List<GoodsInfo>> LL){
List<GoodsInfo> L = new ArrayList<GoodsInfo>();
for(int i=0; i<LL.size();i++){
for(int j=0;j<LL.get(i).size();j++){
L.add(LL.get(i).get(j));
}
}
return L;
}
public static void Packing(BoxInfo b, List<GoodsInfo> realGoodsInfoList, List<Package> resPackageList, List<BoxInfo> L_box, Boolean isXiangZhuang, int buffer){
int CL = b.Length;
int CW = b.Width;
int CH = b.Height;
//将商品按照高度CH约束摞成条状,转为二维问题,存在rectangle中,LL与其同步
List<List<Double>> rectangle = new ArrayList<List<Double>>();
List<List<GoodsInfo>> LL = new ArrayList<List<GoodsInfo>>();
double length_used = 0;
double width_used = 0;
double height_used = 0;
List<GoodsInfo> L = new ArrayList<GoodsInfo>();
//Goods_used_state表示每个Good的使用状态
List<Integer> Goods_used_state = new ArrayList<Integer>();
for(GoodsInfo g:realGoodsInfoList){
Goods_used_state.add(1);
}
while(num_exist(Goods_used_state)>0){
L = new ArrayList<GoodsInfo>();
length_used = 0;
width_used = 0;
height_used = 0;
for(int i=0; i<Goods_used_state.size(); i++){
if(Goods_used_state.get(i) == 1 && height_used+realGoodsInfoList.get(i).Height <= CH){
height_used += realGoodsInfoList.get(i).Height;
length_used = Math.max(length_used, realGoodsInfoList.get(i).Length);
width_used = Math.max(width_used, realGoodsInfoList.get(i).Width);
L.add(new GoodsInfo(realGoodsInfoList.get(i)));
Goods_used_state.set(i,0);
}
}
List<Double> temp_L = new ArrayList<Double>();
temp_L.add(length_used);
temp_L.add(width_used);
rectangle.add(temp_L);
LL.add(L);
}
//摞转成条,用CW去卡,存在length_set中,同步在LLL中
List<List<List<GoodsInfo>>> LLL = new ArrayList<List<List<GoodsInfo>>>();
List<List<GoodsInfo>> temp_LL = new ArrayList<List<GoodsInfo>>();
List<Double> length_set = new ArrayList<Double>();
List<Integer> rec_used_state = new ArrayList<Integer>();
for(int i=0; i<rectangle.size(); i++){
rec_used_state.add(1);
}
double width_used_1 = 0;
double l_bar = 0;
while(num_exist(rec_used_state)>0){
temp_LL = new ArrayList<List<GoodsInfo>>();
width_used_1 = 0;
l_bar = 0;
for(int i=0; i<rec_used_state.size(); i++){
if(rec_used_state.get(i) == 1 && width_used_1+rectangle.get(i).get(1) <= CW){
width_used_1 += rectangle.get(i).get(1);
l_bar = Math.max(l_bar,rectangle.get(i).get(0));
temp_LL.add(Copy.L_good_copy(LL.get(i)));
rec_used_state.set(i,0);
}
}
length_set.add(l_bar);
LLL.add(temp_LL);
}
//计算需要多少箱子
List<Double> box_status = new ArrayList<Double>();
List<List<GoodsInfo>> res_LL = new ArrayList<List<GoodsInfo>>();
box_status.add(0d);
res_LL.add(new ArrayList<GoodsInfo>());
for(int i=0; i<length_set.size(); i++){
int code = 0;
for(int j = 0;j<box_status.size();j++){
if(length_set.get(i)+box_status.get(j) <= CL){
box_status.set(j,box_status.get(j)+length_set.get(i));
pushgoods(breaking(LLL.get(i)),res_LL,j);
code = 1;
break;
}
}
if(code == 0){
box_status.add(length_set.get(i));
res_LL.add(Copy.L_good_copy(breaking(LLL.get(i))));
}
}
//包裹添加,除了最后一个其他都正常添加,最后一个很可能发生填充率较低,故根据其内的商品个数判断是否重新选用耗材
for(int i=0; i<res_LL.size()-1;i++){
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(b));
for(int j=0;j<res_LL.get(i).size();j++) {
temp_package.getGoods().add(new GoodsInfo(res_LL.get(i).get(j)));
}
resPackageList.add(temp_package);
}
//当最后一个商品货物1个或2个时,直接调用现成方法,否则直接装载
List<GoodsInfo> end_goods = Copy.L_good_copy(res_LL.get(res_LL.size()-1));
if(end_goods.size() == 1){
StackingSimple.size_1(L_box, end_goods,isXiangZhuang,resPackageList,buffer);
}else if(end_goods.size() == 2){
StackingSimple.size_2(L_box, end_goods,isXiangZhuang,resPackageList, buffer);
}else{
Package temp_package = new Package();
temp_package.setBox(new BoxInfo(b));
for(int j=0;j<end_goods.size();j++) {
temp_package.getGoods().add(new GoodsInfo(end_goods.get(j)));
}
resPackageList.add(temp_package);
}
}
public static void size_more(List<BoxInfo> boxInfoList, List<BoxInfo> bagList, List<GoodsInfo> realGoodsInfoList,
Boolean isXiangZhuang, List<Package> resPackageList, int buffer){
List<BoxInfo> L;
if(isXiangZhuang){
L = boxInfoList;
} else {
L = bagList;
}
//由于3个及3个以上解空间过大,在此采用启发式方法,先对应每组货物,用一类耗材去装,看最多需要几个耗材
List<Pair<BoxInfo,Integer>> boxesNeed_per_box = new ArrayList<Pair<BoxInfo, Integer>>();
for(BoxInfo b:L){
Pair<BoxInfo,Integer> temp_res = simplePacking(b,realGoodsInfoList);
if(temp_res.getValue() == -1){
continue;
}
boxesNeed_per_box.add(temp_res);
}
//当没有一个耗材能够满足所有商品时,分成单包裹推荐
if(boxesNeed_per_box.size() == 0){
for(GoodsInfo g: realGoodsInfoList) {
List<GoodsInfo> L_g = new ArrayList<GoodsInfo>();
L_g.add(g);
StackingSimple.size_1(boxInfoList, L_g, isXiangZhuang, resPackageList, buffer);
}
return;
}
//从boxesNeed_per_box中挑选最好的耗材,标准是,先选耗材消耗少的,同等耗材数时耗材体积小的优先
int num_box_used = boxesNeed_per_box.get(0).getValue();
for(Pair<BoxInfo,Integer> p:boxesNeed_per_box){
num_box_used = Math.min(num_box_used,p.getValue());
}
int V = Integer.MAX_VALUE;
BoxInfo b = new BoxInfo(boxesNeed_per_box.get(0).getKey());
for(Pair<BoxInfo,Integer> p:boxesNeed_per_box){
if(p.getValue() == num_box_used && V > p.getKey().Volume){
V = p.getKey().Volume;
b = new BoxInfo(p.getKey());
}
}
//耗材选定为b,商品集合为realGoodsInfoList,开始装载
Packing(b, realGoodsInfoList, resPackageList,L,isXiangZhuang,buffer);
}
}
主6、包裹汇总
static void packageSummary(List<Package> resPackageList){
for(Package mPackage : resPackageList) {
if(mPackage.getBox() != null) {
mPackage.setTotalWeight(mPackage.getTotalWeight() + mPackage.getBox().weight);
mPackage.setBoxName(mPackage.getBox().name);
}else{
if(mPackage.getGoods().size() > 0){
if(mPackage.getGoods().get(0).flag == 3){
mPackage.setBoxName("original");
}else{
mPackage.setBoxName("alien");
}
}else{
mPackage.setBoxName(" ");
}
}
Set<String> skuSet = new HashSet<String>();
Map<String, Integer> skuCountMap = new HashMap<String, Integer>();
for(GoodsInfo goodsInfo : mPackage.getGoods()) {
mPackage.setTotalWeight(mPackage.getTotalWeight() + goodsInfo.goodsWeight);
skuSet.add(goodsInfo.sku);
if(!skuCountMap.containsKey(goodsInfo.sku)) {
skuCountMap.put(goodsInfo.sku, 0);
}
skuCountMap.put(goodsInfo.sku, skuCountMap.get(goodsInfo.sku) + 1);
}
mPackage.setSkuList(new ArrayList<String>(skuSet));
mPackage.setSkuCountMap(skuCountMap);
mPackage.setTotalGoodsCount(mPackage.getGoods().size());
}
}