C订单到B订单聚合算法

背景:

        目前c端用户下单,对应的单位是件。也就是一个用户A可能购买15件(只)口红,另外一个用户B购买5只口红。

然后后台B端进货的时候,对应的单位是箱,箱规可能是5件/箱,10件/箱,20件/箱。

为了确保用户购买到的商品全部来自原同一个箱规。即用户A的15只口红不可以来自5件/箱,10件/箱 这两种箱规的组合。

又要考虑到价格最低(前提:20件/箱 单规格价 一定低于  5件/箱的单规格价),所以A可以和B用户组成一箱购买20件/箱  这种规格。

 

算法思路:

需要将这一批用户的所有订单想象成一个长度为n的正整数无序列表list,箱规组合则为一个固定数a,

然后找出无序列表中所有的组合,组合中每个数只能用一次,这些组合的和是a的整数倍,并记录这些组合。

 

思路一:

求出无序列表中所有的子集,然后通过判断子集中的数没有被使用过,且子集的和可以整除a,并记录这些数字,以及组合。

求解的方法有:1、递归。2、利用二进制运算

 

优点:可以罗列所有的可能性,并尝试凑整,不会遗漏任何情况

 

弊端:一个列表的所有子集为2^n次方,如果用for循环遍历,当n大于64的时候,已经是一个非常大的数字,非常影响性能。

而且C端用户参与人数超过64这种场景感觉非常多,甚至可能超过1000人。如果超过1000人,系统无法运算。

代码:只展示核心思想,如何获取所有可能组合

public static List<List<Bean>> getAllList(List<Bean> list) {
    List<List<Bean>> result = new ArrayList<>();
    //子集的个数为2的n次
    long n = (long) Math.pow(2, list.size());
    List<Bean> combine;
    for (long l = 0L; l < n; l++) {
        combine = new ArrayList<Bean>();
        for (int i = 0; i < list.size(); i++) {
            if ((l >>> i & 1) == 1)
            combine.add(list.get(i));
        }
            result.add(combine);
    }
    return result;
}

 

 

思路二:

通过取余的思路做。假设规格数为a,那么所有数就是a*n+b,b<a。然后通过b把所有的数放到一个map中。key为b,value为List,list保存商品数量。

1、当key1+key2=a时,让商品数量一一匹配。

2、然后剩余的数,即key相同的数,看他们能都自行匹配。

3、对剩下的数在用思路一解决。这时候数的数量应该是大大降低了

代码:

/**
     *
     * @param userOrderNumList
     * @param specNumList key-规格数,value-库存
     */
    public static void getResult(List<Integer> userOrderNumList, Map<Integer,Integer> specNumList){
        //未完成的订单,浅拷贝
        List<Integer> unFinishList = userOrderNumList;
        //已完成的订单
        List<Integer> finishList = new ArrayList<>();
 
        for (int i = 0; i < specNumList.size()-1; i++) {
            //获取规格数
            Set<Integer> specNum = specNumList.keySet();
            for (int j = 0; j < userOrderNumList.size()-1; j++) {
                if (unFinishList.size()==0){
                    break;
                }
               //整除,两两相加整除
                compareStart(unFinishList, finishList, userOrderNumList.get(j));
            }
        }
 
    }
 
    public static void compareStart(List<Integer> unFinishList,List<Integer> finishList,int specNum){
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < unFinishList.size(); i++) {
            Integer integer = unFinishList.get(i);
            int b = integer % specNum;
            setMap(map, b, integer);
        }
 
        //余数为0的都可以整除
        finishList.addAll(map.get(0));
        //余数不为0的,相互匹配
        int times = (specNum - 1) / 2;
        for (int i = 1; i <= times; i++) {
            compare(map, i, specNum, finishList);
 
        }
        //剩余所有的数据匹配
        compare2(map, specNum, finishList);
        //取出剩余无法匹配的数据,塞到unFinishList
        setUnFinishList(map, unFinishList);
 
    }
 
    public static void setUnFinishList(Map<Integer, List<Integer>> map, List<Integer> unFinishList){
        unFinishList = new ArrayList<Integer>();
        for(Map.Entry<Integer, List<Integer>> entry : map.entrySet()){
            List<Integer> mapValue = entry.getValue();
            unFinishList.addAll(mapValue);
        }
    }
 
 
    //剩余所有的数据匹配
    public static void compare2(Map<Integer, List<Integer>> map,int specNum, List<Integer> finishList){
        for(Map.Entry<Integer, List<Integer>> entry : map.entrySet()){
            Integer mapKey = entry.getKey();
            List<Integer> mapValue = entry.getValue();
            //TODO 对mapValue从大到小排序
 
            int a = mapValue.size() / specNum;
            int b = mapValue.size() % specNum;
 
            if (a >0){
                finishList.addAll(mapValue.subList(0, a*specNum-1));
                if (b>0){
                    map.put(mapKey, mapValue.subList(a*specNum, mapValue.size()));
                }
            }
 
            //保证剩下的数和 余数的乘积 是 规格的倍数
            mapValue = map.get(mapKey);
            a = mapValue.size() * mapKey / specNum;
            b = mapValue.size() * mapKey % specNum;
//            if (a>0 ){
//                if (&& b==0)
//                finishList.addAll(mapValue);
//                map.remove(mapKey);
//            }
//
//            if ()
        }
    }
 
    /**
     * 取出无法匹配的数据
     * @param map
     * @param key
     * @param specNum
     * @param finishList
     */
    public static void compare(Map<Integer, List<Integer>> map, Integer key,int specNum, List<Integer> finishList){
        List<Integer> list1 = map.get(key);
        List<Integer> list2 = map.get(specNum - key);
 
        if (list1.size() == list2.size()){
            finishList.addAll(list1);
            finishList.addAll(list2);
            map.remove(key);
            map.remove(specNum - key);
            return;
        }
        //TODO 对list1,list2做从大到小排序
        if (list1.size() > list2.size()){
            finishList.addAll(list2);
            finishList.addAll(list1.subList(0, list2.size()-1));
 
            map.remove(key);
            map.put(specNum - key, list1.subList(list2.size()-1, list1.size()));
            return;
        }
 
        if (list1.size() < list2.size()){
            finishList.addAll(list1);
            finishList.addAll(list2.subList(0, list1.size()-1));
 
            map.remove(specNum - key);
            map.put(key, list2.subList(list1.size()-1, list2.size()));
            return;
        }
    }
 
    public static void setMap(Map<Integer, List<Integer>> map, Integer value,Integer key){
        if (null == map){
            return;
        }
        List<Integer> list = map.get(key);
        if (CollectionUtils.isEmpty(list)){
            List<Integer> result = new ArrayList();
            result.add(value);
 
            map.put(key, result);
            return;
        }
        List<Integer> result = map.get(key);
        result.add(value);
        map.put(key, result);
        return;
 
    }

 

思路三:

用递归思想,

1、让无序列表从第一个数开始依次加上下一个数,判断数的和能否整除规格a,如果不能整除则继续加下面一个数,如果能整除则在列表中剔除这几个数,然后从头开始循环,因为此时数的长度变动了,组合可能会变动。

2、如果一轮下来没有任何数满足条件,则开始第二轮循环,循环从第二个数开始,依次加上下一个数。判断数的和能否整除规格a,如果不能整除则继续加下面一个数,如果能整除则在列表中剔除这几个数,然后从头开始循环,此时的循环的第一个数重新回到列表的最前面那个数,因为此时列表的长度变动了,组合可能会变动。

3、每次想加前,先判断这个数是否被使用过。

4、最后对剩下的数用思路一解决。这时候数的数量应该是大大降低了

代码:

public List<List<Bean>> combinationSum(List<Bean> listOriginal, int specNum) {
        if (listOriginal == null || listOriginal.size() == 0)
            return list;
        dfs(listOriginal, specNum);
//        System.out.println(Arrays.toString(finishList.toArray()));
//        System.out.println(Arrays.toString(list.toArray()));
        for (int i = 0; i < list.size(); i++) {
            List<Bean> beans = list.get(i);
            System.err.println(Arrays.toString(beans.toArray()));
        }
        System.err.println("-----------");
        for (int i = 0; i < listOriginal.size(); i++) {
            Bean bean = listOriginal.get(i);
            if (!finishList.contains(bean)){
                System.err.println(bean.toString());
            }
        }
//        System.out.println(Arrays.toString(listOriginal.toArray()));
        return list;
    }
 
    private void dfs(List<Bean> listOriginal, int specNum) {
//        int sum = getSum(ls);
//        if (sum / specNum > 1 && sum % specNum == 0) {
//            list.add(ls);
//            return;
//        }
 
        for (int i = 0; i < listOriginal.size(); i++) {
            if (checkExist(finishList, listOriginal.get(i))){
//                System.err.println("1---exist" + listOriginal.get(i).getNum());
 
                continue;
            }
            int index=i;
 
            if (index == listOriginal.size()){
                return;
            }
            boolean result = dfs(listOriginal, new ArrayList<>(), specNum, index);
            while (result){
                if (flag){
                    index = 0;
                    flag=false;
                }
                result = dfs(listOriginal, new ArrayList<>(), specNum, index);
            }
        }
 
 
    }
 
    private boolean dfs(List<Bean> listTemp, List<Bean> lastTotal, int specNum, int index){
        for (int i = index; i < listTemp.size(); i++) {
            if (checkExist(finishList, listTemp.get(i))){
//                System.err.println("exist" + listTemp.get(i).getNum());
                continue;
            }
            int sum = getSum(listTemp.get(i), lastTotal);
            if (sum/specNum>0 && sum%specNum==0){
                List<Bean> finishListList = new ArrayList<>();
                lastTotal.add(listTemp.get(i));
                finishListList.addAll(lastTotal);
                list.add(finishListList);
                finishList.addAll(finishListList);
                flag=true;
                return true;
 
            }else if (sum/specNum == 0 || sum%specNum > 0){
                if (i >= listTemp.size()){
                    return false;
                }
                lastTotal.add(listTemp.get(i));
                return dfs(listTemp, lastTotal, specNum, i+1);
            }
        }
        return false;
    }
 
    private int getSum(Bean now, List<Bean> lastTotal){
        Integer integer = StreamUtils.sumInteger(lastTotal, Bean::getNum);
        return integer+now.getNum();
    }
 
    private boolean checkExist(List<Bean> listTemp, Bean temp){
        int id = temp.getId();
        for (int i = 0; i < listTemp.size(); i++) {
            int id1 = listTemp.get(i).getId();
            if (id == id1){
                return true;
            }
        }
        return false;
    }

bean代码:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Bean {

    private int num;

    private int id;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值