例子:
datatable 数据为这样
名称 开始时间 动作 次数
A 09:00:00 举手 5
A 15:00:00 扭腰 3
B 08:00:00 抬脚 2
B 11:00:00 举手 6
C 08:00:00 扭脖子 3
想把datatable改成下面这样
序号 开始时间 动作 次数
A 09:00:00;15:00:00 举手 ;扭腰 5;3
B 08:00:00; 11:00:00 抬脚;举手 2;6
C 08:00:00 扭脖子 3
就是把相同序号的合并成一条,求大哥大姐给个基本代码思路 。最好是给个代码或例子。谢谢了!新手小白上路中、
PS: 我们使用 c# vs2010下开发的项目
还有一点是:而且不知道datatable里面不知道序号是有多少列,有可能是1列或多列,就是列数不定
/// <summary> /// 合并Datatable行数据 /// </summary> static void Get() { //申明dt DataTable dt = new DataTable(); //创建字段 dt.Columns.Add("名称", typeof(string)); dt.Columns.Add("开始时间", typeof(string)); dt.Columns.Add("动作", typeof(string)); dt.Columns.Add("次数", typeof(string)); //写入数据 dt.Rows.Add("A", "09:00:00", "举手", "5"); dt.Rows.Add("B", "11:00:00", "举手", "6"); dt.Rows.Add("A", "15:00:00", "扭腰", "3"); dt.Rows.Add("C", "08:00:00", "扭脖子", "3"); dt.Rows.Add("B", "08:00:00", "胎教", "2"); Console.WriteLine("原始数据:"); //输出原数据 for (int i = 0; i < dt.Rows.Count; i++) { Console.WriteLine("{0} {1} {2} {3}", dt.Rows[i]["名称"], dt.Rows[i]["开始时间"], dt.Rows[i]["动作"], dt.Rows[i]["次数"]); } Console.WriteLine("-----------------------------分割线--------------------------------"); //对dt中数据以名称进行升序排序 DataView dv = new DataView(dt); dv.Sort = "名称 asc"; //复制dt的表结构,创建dt2用于存放合并后的数据 DataTable dt2 = dt.Clone(); //存放每个字段值的变量,在下面循环中会多次使用 string Name = string.Empty, Time = string.Empty, Action = string.Empty, Count = string.Empty; Console.WriteLine("排序后的数据:"); //需要循环的是排序后的数据dv,而不是dt for (int i = 0; i < dv.Count; i++) { //输出排序后的数据 Console.WriteLine("{0} {1} {2} {3}", dv[i]["名称"], dv[i]["开始时间"], dv[i]["动作"], dv[i]["次数"]); //除去最后一行数据,其他行数据都跟下一行数据做对比,名称相同的合并在一起并保存到dt2中 if ((i + 1) < dt.Rows.Count) { if (dv[i]["名称"] == dv[i + 1]["名称"]) { Name = dv[i]["名称"] + ";" + dv[i + 1]["名称"]; Time = dv[i]["开始时间"] + ";" + dv[i + 1]["开始时间"]; Action = dv[i]["动作"] + ";" + dv[i + 1]["动作"]; Count = dv[i]["次数"] + ";" + dv[i + 1]["次数"]; dt2.Rows.Add(Name, Time, Action, Count); } } else { //最后一行数据直接添加到dt2 dt2.Rows.Add(dv[i]["名称"], dv[i]["开始时间"], dv[i]["动作"], dv[i]["次数"]); } } Console.WriteLine("-----------------------------分割线--------------------------------"); Console.WriteLine("合并后的数据:"); //再次循环输出dt2(合并后)的数据 for (int i = 0; i < dt2.Rows.Count; i++) { Console.WriteLine("{0} {1} {2} {3}", dt2.Rows[i]["名称"], dt2.Rows[i]["开始时间"], dt2.Rows[i]["动作"], dt2.Rows[i]["次数"]); } }
如果你用的是winform或webform,直接把数据控件的DataSource=dt2就行。希望对你有用。
如果可是大哥,我的名称那一列我只想要一个值(列如--名称是A的有两列,我希望输出后的结果是这样的:
A 09:00:00;15:00:00 举手;扭腰 5;3 就是名称只要一个值A)要怎么写额;还有我确实是用winform开发的,怎么把数据控件的DataSource=dt2做绑定呢?能给些代码么,谢谢了!
@差不哆丨好先生:
//申明dt DataTable dt = new DataTable(); //创建字段 dt.Columns.Add("名称", typeof(string)); dt.Columns.Add("开始时间", typeof(string)); dt.Columns.Add("动作", typeof(string)); dt.Columns.Add("次数", typeof(string)); //写入数据 dt.Rows.Add("A", "09:00:00", "举手", "5"); dt.Rows.Add("B", "11:00:00", "举手", "6"); dt.Rows.Add("A", "15:00:00", "扭腰", "3"); dt.Rows.Add("C", "08:00:00", "扭脖子", "3"); dt.Rows.Add("B", "08:00:00", "胎教", "2"); //对dt中数据以名称进行升序排序 DataView dv = new DataView(dt); dv.Sort = "名称 asc"; //复制dt的表结构,创建dt2用于存放合并后的数据 DataTable dt2 = dt.Clone(); //存放每个字段值的变量,在下面循环中会多次使用 string Name = string.Empty, Time = string.Empty, Action = string.Empty, Count = string.Empty; //需要循环的是排序后的数据dv,而不是dt for (int i = 0; i < dv.Count; i++) { //输出排序后的数据 Console.WriteLine("{0} {1} {2} {3}", dv[i]["名称"], dv[i]["开始时间"], dv[i]["动作"], dv[i]["次数"]); //除去最后一行数据,其他行数据都跟下一行数据做对比,名称相同的合并在一起并保存到dt2中 if ((i + 1) < dt.Rows.Count) { if (dv[i]["名称"] == dv[i + 1]["名称"]) { //Name = dv[i]["名称"] + ";" + dv[i + 1]["名称"]; Name = dv[i]["名称"].ToString();//如果名称这一列只要一个值,不用拼接就可以 Time = dv[i]["开始时间"] + ";" + dv[i + 1]["开始时间"]; Action = dv[i]["动作"] + ";" + dv[i + 1]["动作"]; Count = dv[i]["次数"] + ";" + dv[i + 1]["次数"]; dt2.Rows.Add(Name, Time, Action, Count); } } else { //最后一行数据直接添加到dt2 dt2.Rows.Add(dv[i]["名称"], dv[i]["开始时间"], dv[i]["动作"], dv[i]["次数"]); } } //这里就是绑定数据源,也就是指定名称为dataGridView1的控件的数据源为:dt2 this.dataGridView1.DataSource = dt2; //这里是指定控件的第一二三四列显示标题 this.dataGridView1.Columns[0].HeaderText = "名称"; this.dataGridView1.Columns[1].HeaderText = "开始时间"; this.dataGridView1.Columns[2].HeaderText = "动作"; this.dataGridView1.Columns[3].HeaderText = "次数";
是这样的效果吗
@程序人生,永无止境: 是的,我就是想要dt表那样的效果但并不需要把它显示到DataGridView里面,谢谢大哥!如果我希望是得到dt表,是不是把方法写成有返回值的方法,方法的最后 直接return dt 就好了,是这样么? 还有个问题,在名称的这一列,里面的值不一定只有ABC 3列,有可能是ABCDEFG,也可能只有A列,就是值不定,我见你在 写入数据dt.Rows.Add()方法 的那里,直接是写死了,怎么修改名称的呢
@差不哆丨好先生: 是这样的,如果你只是希望得到dt,那么就定义一个有返回值的方法,返回值类型为DataTable,在方法最后直接return dt 就行。名称这一列只是一个字段而已,我例中所写dt.Rows.Add()只是针对表格dt做一个数据写入的操作,至于你想写入多少行数据,那就在后面继续写就行了,Add方法中的参数的个数就是你当前dt中的列数。dt.Rows.Add()里面的值之所以写死只不过是我没有从其他地方拿数据值,如果你的数据是动态的,那就定义几个变量,然后根据情况给变量赋值,再把变量按顺序传进来就行了。
@程序人生,永无止境: 好的,谢谢 !
@程序人生,永无止境: dt.Rows.Add()这个方法里面的数据是动态,怎么定义几个变量啊?研究了1天了还是没研究出来额,麻烦帮贴点代码思路额、还有 if (dv[i]["名称"] == dv[i + 1]["名称"]) 这个比较我的怎么都跑不进去的....
@差不哆丨好先生:
public void Test() { //比如我现在有一个现成的数据集合 List<ProductType> list = new List<ProductType>() { new ProductType(){TypeId=1,Name="手机"}, new ProductType(){TypeId=2,Name="钱包"}, new ProductType(){TypeId=3,Name="电脑"}, new ProductType(){TypeId=4,Name="自行车"}, new ProductType(){TypeId=6,Name="自行车"}, }; System.Data.DataTable dt = new System.Data.DataTable(); dt.Columns.Add("编号", typeof(int)); dt.Columns.Add("名称", typeof(string)); int TypeId = 0; string Name = string.Empty; // 1. 动态向dt中插入数据 //讲数据集合循环插入到dt中 foreach (var item in list) { //直接赋值 dt.Rows.Add(item.TypeId, item.Name); //或者 //TypeId = item.TypeId; //Name = item.Name; //dt.Rows.Add(TypeId, Name); } int dtCount = dt.Rows.Count; /// 2. 如何让 if (dv[i]["名称"] == dv[i + 1]["名称"]) 怎么跑的进去 /// 我这里没有DataView的变量,就用list来演示 string mes = string.Empty; for (int i = 0; i < list.Count(); i++) { if (i + 1 < list.Count()) { if (list[i].Name == list[i + 1].Name) { mes = string.Format("第{0}条数据的Name属性值与第{1}条数据的Name属性值相等", i + 1, i + 2); } } } }
要让dv[i]["名称"]==dv[i]["名称"]的条件是让相邻条两条数据中的"名称"的值相等。
我在list集合中最后两条数据的Name是一样的,所以这个判断就会进去。
http://stackoverflow.com/questions/12278978/combining-n-datatables-into-a-single-datatable
大哥,能否提供些详细的中文说明例子啊,英文实在是短板
还是不明白啊,大哥。能否提供个例子是返回datatable表的,而不是Console.WriteLine()方法返回的
@差不哆丨好先生: 这个例子里的query.ToList()的结果就是一个DataRow的集合了
@差不哆丨好先生: 这个写法挺好的 节省了很多代码。思路也清晰
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication14
{
class Program
{
static void Main(string[] args)
{
//造示例数据
DataTable dt = new DataTable();
dt.Columns.Add("名称", typeof(string));
dt.Columns.Add("开始时间", typeof(string));
dt.Columns.Add("动作", typeof(string));
dt.Columns.Add("次数", typeof(string));
dt.Rows.Add("A", "09:00:00", "举手", "5");
dt.Rows.Add("A", "15:00:00", "扭腰", "3");
dt.Rows.Add("B", "08:00:00", "抬脚", "2");
dt.Rows.Add("B", "11:00:00", "举手", "2");
dt.Rows.Add("C", "08:00:00", "扭脖子", "6");
dt.Rows.Add("C", "09:00:00", "提臀", "5");
//以名称进行分组
IEnumerable<IGrouping<string, DataRow>> f = dt.AsEnumerable().GroupBy(A => A.Field<string>("名称").ToString());
//克隆一个和dt一模一样的数据表
DataTable dt2 = dt.Clone();
dt2.Clear();
//遍历分组后的数据
foreach (IGrouping<string, DataRow> item in f)
{
string 开始时间 = "";
string 动作 = "";
string 次数 = "";
foreach (DataRow item2 in item)
{
开始时间 += item2.Field<string>("开始时间") + ";";
动作 += item2.Field<string>("动作") + ";";
次数 += item2.Field<string>("次数") + ";";
}
dt2.Rows.Add(item.Key, 开始时间, 动作, 次数);
}
//完成
Console.WriteLine(dt2.Rows.Count);
}
}
}
园豆全是我的啦
逗比,你仔细看下到底是不是人家要的结果
谢谢大哥,辛苦啦,代码我还得研究下才能结帖额。