分组批销单模块业务,内部算法

背景:获取合并批销单数据,对数据进行分组合并展示,每组数据12个,可以扩展2个位置,用于业务人员筛选产品发往快递公司

规则:①相同供应商相同发货时间一起展示,每组不能超过规定数据

     ②相同供应商相同时间的数据如果被分到2组,那么两组数据需要相连

     ③必须同一发货时间的在一组中;最后每一组数据需要匀称,不能呈现出特别多与特别少。

     ④以发货时间为准,相同发货时间的尽量放在一起,并且以发货时间进行排序

     ⑤最后零碎发货时间的放在一组

     ⑥最后如果零碎中有与大组中发货时间相同的则放在一起,但每组数据不能超过15

思路:创建一个大list保存已经完美拍好的list

  一、拿100%满足条件

    ①先拿出100%符合条件,拿出多少条根据算法计算出来,放到大List中

    ②拿出100%满足的剩余的放在一组中

  二、填补

    ①取出大List中不满数组长度的List,对其进行填充;填充时不能把同一供应商同一时间的拆开;最大长度12+2;这块是另外一个算法,如何匹配到完美的填补

  三、处理大量剩余

    ①剩余的处理与第二部类似,只不过,第二部是某单个数据在一个大的集合中查找,而这步则把集合中每一个小集合匹配成完美的组放入大Lst中

    ②同供应商同时间的必须放在一起,每组数据相加大于最大长度且小于最大长度+扩展长度 ---------算法

    ③由于业务数据原因有很大概率处理到最后会剩余几条数据如何处理?

  四、微调、剩余归类---这里是另外一个算法

    ①第三步中剩下的数据中如果有大于3的则独立成一组,因为上步中已经把所有数据都匹配的近乎完美所以大于3肯定是在数组中放不下的

    ②把所有微小的颗粒放在同一组,装进大lst中

  五、按大组中每个list的第一条数据的日期排序并按先后顺序给予组号

算法:

一、通过取整与取余对数组长度进行配比得到最优的情况

  首先考虑到不满一组时的数组长度处理,这关系到数据遍历时拿数据

  计算最优配比:比如25条数据,数组长度12扩展位2--取整2余1,此时如果我一组12条数据会落单一条这是非常不希望看到的结果

  此时如果每组13条数据就可以得到最好的结果

 1     /// <summary>
 2         /// 得到真实数组长度的方法
 3         /// </summary>
 4         /// <param name="arrayLength">数组长度</param>
 5         /// <param name="maxLen">最大长度</param>
 6         /// <param name="extSeat">扩展长度</param>
 7         /// <param name="arr">数组个数</param>
 8         /// <param name="rem">数组剩余</param>
 9         /// <param name="trueArrLength">真实数组长度</param>
10         /// <param name="isExt"></param>
11         private void trueArrayProperty(int arrayLength, int maxLen, int extSeat, ref int arr, ref int rem, ref int trueArrLength)
12         {
13             //真实组数
14             if (arrayLength < maxLen)
15             {
16                 arr = 1;
17                 rem = arrayLength;
18             }
19             else
20             {
21                 arr = arrayLength / maxLen;
22                 //余数
23                 rem = arrayLength % maxLen;
24             }
25             //真实的数组长度
26             trueArrLength = maxLen;
27             for (int ai = 1; ai <= extSeat; ai++)
28             {
29                 int a1 = arr * ai;
30                 if (rem == 0) { break; }
31                 if (a1 > rem)
32                 {
33                     trueArrLength = trueArrLength + ai;
34                     arr = arrayLength / trueArrLength;
35                     //余数
36                     rem = arrayLength % trueArrLength;
37                 }
38             }
39         }

算法二:摘数据,采用递归也是没辙中想到的辙,如果不使用递归,从大集合中遍历大集合会造成引用类型循环引用的问题

  ①将源数据按供应商和时间分组,拿到分组后结果集就可以拿到每组有多少条数据;

  ②数组长度按每组需要大于等于Maxlen且小于等MaxLen+extSeat

  ③while(boolean)的用意在于可能不能一次性匹配上数据,可能需要多次叠加才可以得到满意的数组

  ④由于业务数据原因和分组匹配规则最后一定会出现不可能全部把souceDatas吃完,所以就用了zOther存储这些另类数据,保证退出

 1 /// <summary>
 2         /// 递归剩余数据
 3         /// </summary>
 4         /// <param name="sourceDatas">源数据</param>
 5         /// <param name="resultDatas">大lst</param>
 6         /// <param name="maxLen">最大长度</param>
 7         /// <param name="extSeat">扩展位</param>
 8         /// <param name="zOther">杂项处理</param>
 9         private void RecursionDatas(List<ResponseSaleOrderJoinModel> sourceDatas, List<List<ResponseSaleOrderJoinModel>> resultDatas,
10             int maxLen, int extSeat, List<ResponseSaleOrderJoinModel> zOther)
11         {
12             if (sourceDatas.Count == 0)
13             {
14                 return;
15             }
16             List<ResponseSaleOrderJoinModel> curItem = new List<ResponseSaleOrderJoinModel>();
17             var dataGroup = sourceDatas.GroupBy(e => new { e.saleOrderDate, e.ssellerID }).OrderByDescending(e => e.Count());
18             var groupFirst = dataGroup.First();
19             curItem = sourceDatas.Where(e => e.saleOrderDate == groupFirst.Key.saleOrderDate && e.ssellerID == groupFirst.Key.ssellerID).ToList();
20             sourceDatas = sourceDatas.Except(curItem).ToList();
21             var group = sourceDatas.Where(e => e.saleOrderDate == curItem.First().saleOrderDate).GroupBy(e => new { e.saleOrderDate, e.ssellerID });
22             while (curItem != null)
23             {
24                 foreach (var item in group)
25                 {
26                     //只匹配正好的
27                     if (item.Count() >= (maxLen - curItem.Count) && item.Count() <= (maxLen + extSeat - curItem.Count))
28                     {
29                         curItem.AddRange(item);
30                         resultDatas.Add(curItem);
31                         sourceDatas = sourceDatas.Except(curItem).ToList();
32                         curItem = new List<ResponseSaleOrderJoinModel>();
33                         break;
34                     }
35                 }
36                 //一轮过后,如果没匹配上,则可能过大而剩余中没有小数
37                 if (curItem.Count >= maxLen)
38                 {
39                     resultDatas.Add(curItem);
40                     sourceDatas = sourceDatas.Except(curItem).ToList();
41                     curItem = new List<ResponseSaleOrderJoinModel>();
42                 }
43                 else if (curItem.Count < maxLen && curItem.Count > 0)
44                 {
45                     //一轮过后,如果没匹配上,则可能数据量过小而剩余中没有能够匹配上的
46                     var dataFirst = group.FirstOrDefault(e=>e.Key.saleOrderDate==curItem.First().saleOrderDate);
47                     if (dataFirst == null)
48                     {//如果没有找到同类,则有可能是与其它时间相同,也有可能与其它不同。如何处理
49                         zOther.AddRange(curItem);
50                         curItem = new List<ResponseSaleOrderJoinModel>();
51                         break;
52                     }
53                     curItem.AddRange(dataFirst);
54                     sourceDatas = sourceDatas.Except(dataFirst).ToList();
55                 }
56                 else
57                 {
58                     break;
59                 }
60                 group = sourceDatas.Where(e => e.saleOrderDate == curItem.First().saleOrderDate).GroupBy(e => new { e.saleOrderDate, e.ssellerID }).ToList();
61             }
62             RecursionDatas(sourceDatas, resultDatas, maxLen, extSeat,zOther);
63         }

算法三:同样是集合找集合的问题,使用了降级处理思路

  ①在进入递归前,我先把zOther过滤了一次,按同商同时分组后,数据量大于3的独立出一组,以降低递归复杂度

  ②这时数据里会出现2种情况,第一种是与大list种的时间相同,这类数据是可以归并到list中的,而剩余的则是与大list中其他数组数据时间不同的,这类数据需要都放在一组中

 1 private void RecursionOtherDatas(List<ResponseSaleOrderJoinModel> otherDatas, List<List<ResponseSaleOrderJoinModel>> resultDatas,
 2             List<ResponseSaleOrderJoinModel> zz) {
 3             if (otherDatas.Count == 0) {
 4                 return;
 5             }
 6             var otherGroup = otherDatas.GroupBy(e => new { e.saleOrderDate, e.ssellerID });
 7
 8             var groupFirst = otherGroup.First();
 9             var data = otherDatas.Where(e => e.saleOrderDate == groupFirst.Key.saleOrderDate && e.ssellerID == groupFirst.Key.ssellerID).ToList();
10             foreach (var item in resultDatas.OrderBy(e=>e.Count))
11             {
12                 if (item.Count == 15) { break; }
13                 if (item.Any(e => e.saleOrderDate == groupFirst.Key.saleOrderDate))
14                 {
15                     if (item.Count + data.Count <= 15)
16                     {
17                         item.AddRange(data);
18                         otherDatas = otherDatas.Except(data).ToList();
19                         groupFirst = null;
20                         break;
21                     }
22                 }
23             }
24             if (groupFirst != null) {
25                 zz.AddRange(data);
26                 otherDatas = otherDatas.Except(data).ToList();
27             }
28             RecursionOtherDatas(otherDatas, resultDatas, zz);
29         }

后记:整个业务模块用时将近一个月,但这套代码只写了4天。前边大部分时间由于产品经理的需求一直在变每当我开发出一套算法他就变了挂,所以前边一直在改改改,索性我比较机智,并不是在代码的基础上改,

而是每次都新建一个方法。后来改烦了,索性直接越级找大boss问清楚了真正的需求,最后落定出这套算法。

  这次的教训不管是大功能还是小功能都应该落实到文档上,把自己理解的东西写清楚,不管是自己忘了查看也好,未来扯皮也摆还都是有好处的

时间: 2024-10-02 22:30:14

分组批销单模块业务,内部算法的相关文章

LayUi表单模块无法正常显示

问题: 当我们再使用LayUI的Form表单模块时,我们会把自己需要的表单赋值到我们的页面中,但是会出现无法正常显示的问题,如下: 出现原因: LayUI官方文档也明确表示:“当你使用表单时,layui 会对 select.checkbox.radio 等原始元素隐藏,从而进行美化修饰处理.但这需要依赖于 form 组件,所以你必须加载 form.” 所以我们必须加载form模块,才能使它完整地渲染出来. 解决方法: 在你js文件的代码最外层,把需要用到的模块 layui.use 预加载一下,如

UVA 572 -- Oil Deposits(DFS求连通块+种子填充算法)

UVA 572 -- Oil Deposits(DFS求连通块) 图也有DFS和BFS遍历,由于DFS更好写,所以一般用DFS寻找连通块. 下述代码用一个二重循环来找到当前格子的相邻8个格子,也可用常量数组或者写8条DFS调用. 下述算法是:种子填充(floodfill) 两种连通区域 四连通区域:从区域内一点出发,可通过上.下.左.右四个方向的移动组合,在不越出区域的前提下,能到达区域内的任意像素 八连通区域:从区域内每一像素出发,可通过八个方向,即上.下.左.右.左上.右上.左下.右下移动的

24、【华为HCIE-Storage】--Hyper Snapshot(块业务)

------------------------------------重要说明------------------------------------ 以下部分内容来网络,部分自华为存储官方教材 具体教材内容请移步华为存储官网进行教材下载 网络引用内容无法找到原创,如有侵权请通知 ------------------------------------重要说明------------------------------------ 随着计算机技术的发展,数据备份的重要性也逐渐凸显.在最初的数据

30、【华为HCIE-Storage】--Hyper Metro(双活【块业务】)

------------------------------------重要说明------------------------------------ 以下部分内容来网络,部分自华为存储官方教材 具体教材内容请移步华为存储官网进行教材下载 网络引用内容无法找到原创,如有侵权请通知 ------------------------------------重要说明------------------------------------ HyperMetro特性为用户提供了灵活且强大的数据容灾功能,

django Form表单模块实例(一)

定义forms表单: from django import forms class ContactForm(forms.Form):    subject = forms.CharField(max_length=100)    message = forms.CharField(widget=forms.Textarea)    sender = forms.EmailField()    cc_myself = forms.BooleanField(required=False) 定义vie

★★IDEA使用教程(第一阶段:单模块部署)

@author:rookie 0.安装idea并且破解; 1.配maven和svn命令; 配maven图 配svn:如果没有svn命令则需要去下载svn,然后指向它(下载最新版小乌龟即可) 2.建空项目,配jdk; 配jdk 3.检出项目,检出后会提醒是否打开,点no; 选择对应的项目检出到第二步建的项目路径内 选1.8,然后等待检出... 要选no 4.点击添加模块将检出的项目添加进来,就可以看见了; 打开项目配置 导入刚才检出的项目(idea里面叫模块),完成后就可以看见它了 等它解决mav

红黑树 结构内部算法解析

/** From CLR */ private void fixAfterInsertion(Entry<K,V> x) { x.color = RED; while (x != null && x != root && x.parent.color == RED) {//当前插入节点的父节点是 当前节点祖先节点的 左子节点 进入 if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {//得到当前节点祖先节点的右子

八种排序算法(内部排序)

八种排序算法很长时间没有使用了,今天做一个总结,方便以后自己用的时候参考. 这八种排序算法都是内部算法,这八种排序算法分别是: 1. 插入排序 1)直接插入排序 2)希尔排序 2.选择排序 1)简单选择排序 2)堆排序 3.交换排序 1)冒泡排序 2)快速排序 4.归并排序 5.基数排序 一.直接插入排序 将一个记录插入到已经排好序的有序表中,从而得到一个新的.记录数增1的有序表.在实际操作中,先将序列的第一个记录看成是一个有序的子序列,然后从第二个.第三个.……记录逐个进行插入,直至整个序列有

点在多边形内算法,C#判断一个点是否在一个复杂多边形的内部

判断一点是否在不规则图像的内部算法,如下图是由一个个点组成的不规则图像,判断某一点是否在不规则矩形内部,先上效果图 算法实现如下,算法简单,亲试有效 public class PositionAlgorithmHelper { /// <summary> /// 判断当前位置是否在不规则形状里面 /// </summary> /// <param name="nvert">不规则形状的定点数</param> /// <param n