接到一个需求,在数据环境中,需要做出按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;
}