C#多个DataTable根据某一列匹配,其余字段相加求和的高效算法。

6 篇文章 0 订阅

接到一个需求,在数据环境中,需要做出按1-12,可以选择 今年与去年两年 任意月度的数据进行对比。但是,这些数据又不存在于数据库中,不能直接求和、原数据 就在datatable中保存。所以就需要有多个DataTable相加的办法。但是,用datatable一个个循环加,效率不可恭维。绞尽脑汁想出一个办法,整个循环一次,就将最终的Table取出。

具体功能效果、大致如下

根据ID匹配  ID相同的行,再将 col1  和 col2 对应相加,得到总的table。

1、算法描述

这边是根据用户选中月份来统计,所以讲一下大致的思路。

将匹配的id从小到大排好序,并且知道用户选中的几个月。

然后 写一个循环,在循环中,同时循环这几个月份,并记录初始行号,并获取到id的最小值。

若是,匹配到ID同样是最小的,则将这两行的字段相加。

这样,每次循环都获取到当前id最小的行。加入新的tabel。

然后将之前的记录的循环行号+1。

那么第二次循环, 这些+1的就从第二行开始循环,依次类推,匹配到就+1。

若是行号,超出了当前月份最大表,就在循环中剔除,再次循环就跳过这张表。

直到所有表都被剔除时,结束,输出。

文字描述总是难以理解,来看一下 伪代码。

        public DataTable MergeDataTableByMonth1(Dictionary<int, DataTable> dicTable, DataTable dtBack, string year)
        {
            //这个monthYear存的是当前年度,用户选中的月份、
            List<int> monthYear = month[year];
            //用来储存月份及对应的行号  超过即移除,初始都为0  key为我们的月份。
            Dictionary<int, int> count = new Dictionary<int, int>();
            //循环count的数量,count里面有值说明还需要循环
            while (count.Count() > 0)
            {
                //记录DataRow合计值
                DataRow drInsert = dtBack.NewRow();
                //记录最小的id
                decimal smallId = 0;
                //记录最小id匹配需要updata的key
                List<int> UpdateKey = new List<int>();
                //记录超过table行上限需要remove的key
                List<int> RemoveKey = new List<int>();

                //循环每个月 获取 最小code的合计值 
                foreach (int key in monthYear)
                {
                    //并且 记录  需要 更新的key 已经需要移除的 key
                }
                //标记列增加 1  代表下次循环从下一行开始
                foreach (int key in UpdateKey)
                {
                    count[key] += 1;
                }
                //删除列  除去操作 代表这些月份已经全部相加
                foreach (int key in RemoveKey)
                {
                    monthYear.Remove(key);
                    count.Remove(key);
                }
                //最后将合计值统计插入返回Table
                dtBack.ImportRow(drInsert);
            }
            return dtBack;
        }

 

总结,相对于每次都要去循环,然后再匹配ID,效率已经快了非常多,测试 1000行数据,12张表相加,耗时0.2s左右,当然肯定还有更优的办法,希望大佬提供帮助。上述内容纯属自学。

注意,前提,排序好很重要。

 

最后附上实现代码!

villagecode即为我的ID,不是数字类型但也排好序了。前提!!排序!!增加了各种情况的判断。当然要用肯定还得自己修改。。

 public DataTable MergeDataTableByMonth(Dictionary<int, DataTable> dicTable, DataTable dtBack, string year)
        {
            List<int> monthYear = month[year];
            //用来储存月份及对应的行号  超过即移除
            Dictionary<int, int> count = new Dictionary<int, int>();
            foreach (int key in monthYear)
            {
                count.Add(key, 0);
            }

            if (dicTable.Count() > 0)
            {
                while (count.Count() > 0)
                {
                    //记录DataRow合计值
                    DataRow drInsert = dtBack.NewRow();
                    //记录最小的code
                    decimal smallCode = 0;
                    //updata的key
                    List<int> UpdateKey = new List<int>();
                    //remove的key
                    List<int> RemoveKey = new List<int>();

                    //循环每个月 获取 最小code的合计值 
                    foreach (int key in monthYear)
                    {
                        DataTable dt = dicTable[key];
                        if (dt.Rows.Count > count[key])
                        {
                            DataRow dr = dtBack.NewRow();
                            //循环到 第一个月份 code不为0的情况 
                            while (dr["villagecode"].ToDecimal() == 0)
                            {
                                if (dt.Rows.Count > count[key])
                                {
                                    dr = dt.Rows[count[key]];
                                    if (dr["villagecode"].ToDecimal() != 0)
                                    {
                                        //第一个月
                                        if (smallCode == 0)
                                        {
                                            smallCode = dr["villagecode"].ToDecimal();
                                            drInsert = dr;
                                            UpdateKey.Add(key);

                                        }
                                        //其余 月份 对比  组织较小
                                        else if (dr["villagecode"].ToDecimal() < smallCode)
                                        {
                                            drInsert = dr;
                                            UpdateKey.Clear();
                                            UpdateKey.Add(key);
                                        }
                                        else if (dr["villagecode"].ToDecimal() == smallCode)
                                        {
                                            drInsert = MargeDataRow(drInsert, dr);
                                            UpdateKey.Add(key);
                                        }
                                    }
                                    else
                                    {
                                        count[key] += 1;
                                    }
                                }
                                else
                                {
                                    RemoveKey.Add(key);
                                    break;
                                }
                            }

                        }
                        else
                        {
                            RemoveKey.Add(key);
                        }
                    }
                    //标记列增加 1
                    foreach (int key in UpdateKey)
                    {
                        count[key] += 1;
                    }
                    //删除列除去
                    foreach (int key in RemoveKey)
                    {
                        monthYear.Remove(key);
                        count.Remove(key);
                    }
                    dtBack.ImportRow(drInsert);
                }

            }

            return dtBack;
        }

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值