注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

樱之花

叶散的时候,你明白欢聚;花谢的时候,你明白青春.

 
 
 

日志

 
 
关于我

分类中“我的实验室”是我在日常工作中的一些知识总结,有些写的比较匆忙,可能大家在阅读时会产生困扰,后期有时间我会重新整理编辑,谢谢大家的到访,您们的支持是我前进的动力!

网易考拉推荐

006 DATATABLE按关键字分组的多次小计和总计的算法  

2011-11-14 21:41:44|  分类: 我的实验室 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

接到一个ASP.NET报表需求,按某关键字分组多次小计,而且在最后要加一行总计,我做报表用的是最原始的方法,GRIDVIEW+DATATABLE,因此必须对DATATBLE处理。想到的第一种方法是最常见的行循环求和计算,这种算法思路简单最常用,不过我一直觉得这样的效率不好,看到DATATABLE有Compute()方法,可以使用SUM函数,感觉这里面可以搞点名堂出来。因此呢,花了一整天设计了几种方法,发现执行效率都不一样。正因为发现每想出一种方法来执行效率都在提高,这才使我有兴趣继续研究下去。想到第2种方法,是把每一个分组复制给临时表datatable,小计后再复制给最终表dtend,接着清空临时表,继续循环判断。这时得出的结果,虽然执行效率要比第1种方法高,但观察发现dtend的行复制有点多余,因为这些行都在原表中存在,原表只是缺少每个分组的小计,还是可以改进的,于是,在临时表处理的时候把小计都保存到一个新表dtsum中,并且记录每次分组的界限索引,这样在循环结束时,直接在原表中找到处理后的界限索引把每个分组的小计插入到该索引的行位置,这样组成了一个最终表。但是,我还是不满足这样的效率,总觉得代码中还是可以有优化的地方。想了很久头都大了,看到临时表处理那块还是有行复制的处理,想想是不是有什么办法代替这一步呢?最后试着看是不是可以记录每个分组的关键字,通过Compute()方法的filter来取关键字的小计,记录到表dtsum中,然后再用第3种方法后面处理的办法插入到原表中,最终这样的方法也是可行的,速度明显提高了,但只是有个缺点是,它是和分组的数量成反比的,分组数量越大,执行效率就变低,因为要处理的数据表变多了,但一般情况下分组数量是有限的,因此第3和第4种方法是我的最终的选择。具体的结果我还是要进一步测试才能得出最终正确的结论。我还是希望能够发现更好的办法,不过随着一天的结束,我也停下了暂时的思考。

以上只是我的一个简单总结,记录今天想出的思路,怕自己过了今天又忘记了及时写下,结果写的有点零乱。

图示需求:

原表:

006 DATATABLE多次小计和总计的算法 - freesky - 樱之花 yinzhihua2008

 需要计算生成的表:
达成率=送货金额/订单金额
订单数量加送货数量=订单数量+送货数量
例子按区域分组共有三个分组,及101,102,103,要对每个分组生成一个小计,并且最后加一个总计。

006 DATATABLE多次小计和总计的算法 - freesky - 樱之花 yinzhihua2008


第1种方法思路:
数据源表dt;变量:开始索引browindex,当前索引rowindex
1)取dt第一行赋给dttemp
2)从dt第2行开始循环判断,判断每行是否与dttemp的关键字列内容相等
若相等,则复制该行给dttemp,rowindex加1;
若不相等,则计算从browindex开始到rowindex结束的行的合计,dttemp新增一行,复制合计数据给该行,再新增一行,把当前行复制给该行,因此rowindex加2,browindex赋值rowindex,重新确定行的开始索引。
3)如果循环到了dt最后一行,计算browindex到rowindex行的合计,dttemp新增一行保存合计数据。这一步如果不处理,会丢失最后一个分组的小计。
4)计算dt所有行的合计,复制给dttemp的新增行。

第2种方法思路:
通过临时表dttemp来中转分组数据,计算小计后赋值给dtend,最后通过Compute()方法计算总计
1)取dt第一行关键字列赋值给变量tempstr
2)从dt第1行开始循环判断,判断每行是否与tempstr的关键字列内容相等
若相等,则复制改航给dttemp
若不相等,则计算dttemp的小计,并把dttemp复制给dtend。接着,清空dttemp行,把当前行复制给dttemp,并且把关键字列的值赋值给tempstr
3)如果循环到dt最后一行,计算最后一个分组的小计,并把dttemp复制给dtend
4)通过Compute()方法计算dt总计

第3种方法思路:

1)将原表dt第一行的关键字赋值给变量tempstr
2)然后用tempstr循环比较dt第一行关键字
若相等,则把dt表的当前行复制给临时表dttemp;
若不相等,则计算已构成的临时表dttemp的小计,把小计行添加到分组表dtsum中。同时,记录当前dt的索引到一个数组中(因为后面要把每个分组小计插入到原表中,所以要记录这时的索引),暂且叫它分组界限索引数组arri。清空dttemp行,下面还要继续用到这个临时表。这一步骤最后,把当前行复制给临时表,否则这行会丢失。
3)如果循环到了dt最后一行了,一定记得对临时表做个小计,不然会丢失掉最后一个分组的小计。
4)根据分组小计表和界限索引数组的数据,把它们插入到原表中。根据arri记录的索引从头开始插入时,因为插入一行原表就要增加一行,所以插入的位置要注意已插入的数目的变化,因而要对arri记录的索引加上循环的变量值。
5)计算dt表的总计。
注意:分组小计和最后dt表的总计用了datatable的Compute()方法,都新增了一个新行来记录。
相对思路2,改进了,只记录每个分组的小计行,根据界限索引把分组小计插入回原表中

第4种方法思路:
1)将原表dt第一行的关键字赋值给变量tempstr
2)然后用tempstr循环比较dt第一行关键字
若不相等,记录当前dt的索引到一个数组中(因为后面要把每个分组小计插入到原表中,所以要记录这时的索引),暂且叫它分组界限索引数组arri。记录分组关键字到数组arrkeyvalue中,把当前行关键字复制给tempstr。
3)根据分组的关键字数组arrkeyvalue计算每个分组的小计结果保存到dtsum中。
4)将dtsum按界限索引数组插入回原表dt。
5)计算表dtsum的小计,结果行追加到dt表中得到了总计。

注意:相对思路3,改进的是,取消临时表dttemp的处理,只记录界限索引和分组的关键字数组,根据关键字数组对原表分析,用Compute()方法来计算小计和总计。缺点是,一旦分组数目变大,执行效率会明显降低,这并不是最好的方法。

自己的总结:
1.在分组数固定时候(<=10),行数越多执行效率结果是,4>3>2>1;
2.在行数固定时,分组数越多执行效率结果是,3>2>1>4;
3.在分组数固定时候(高>=10),行数越多执行效率结果同2。

  评论这张
 
阅读(2091)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017