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

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

具体功能效果、大致如下

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

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

1、算法描述

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

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

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

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

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

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

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

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

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

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

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

                //循环每个月 获取 最小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 dicTable, DataTable dtBack, string year)
        {
            List monthYear = month[year];
            //用来储存月份及对应的行号  超过即移除
            Dictionary count = new Dictionary();
            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 UpdateKey = new List();
                    //remove的key
                    List RemoveKey = new List();

                    //循环每个月 获取 最小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;
        }

 

你可能感兴趣的:(C#,.net)