首页 新闻 会员 周边

C# DataTable合并重复列(不管里面的值重复不重复,都合并值,用分号隔开)。

0
悬赏园豆:100 [已解决问题] 解决于 2016-12-21 13:01

例子:  

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列或多列,就是列数不定

差不哆丨好先生的主页 差不哆丨好先生 | 初学一级 | 园豆:0
提问于:2016-12-20 08:00
< >
分享
最佳答案
0
        /// <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就行。希望对你有用。

收获园豆:100
龙行天涯 | 小虾三级 |园豆:1794 | 2016-12-20 15:03

如果可是大哥,我的名称那一列我只想要一个值(列如--名称是A的有两列,我希望输出后的结果是这样的:

A     09:00:00;15:00:00      举手;扭腰     5;3    就是名称只要一个值A)要怎么写额;还有我确实是用winform开发的,怎么把数据控件的DataSource=dt2做绑定呢?能给些代码么,谢谢了!

差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-20 22:07

@差不哆丨好先生: 

            //申明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 = "次数";

 

 

是这样的效果吗

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-21 09:01

@程序人生,永无止境: 是的,我就是想要dt表那样的效果但并不需要把它显示到DataGridView里面,谢谢大哥!如果我希望是得到dt表,是不是把方法写成有返回值的方法,方法的最后 直接return dt 就好了,是这样么? 还有个问题,在名称的这一列,里面的值不一定只有ABC 3列,有可能是ABCDEFG,也可能只有A列,就是值不定,我见你在  写入数据dt.Rows.Add()方法 的那里,直接是写死了,怎么修改名称的呢

差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-21 12:09

@差不哆丨好先生: 是这样的,如果你只是希望得到dt,那么就定义一个有返回值的方法,返回值类型为DataTable,在方法最后直接return dt 就行。名称这一列只是一个字段而已,我例中所写dt.Rows.Add()只是针对表格dt做一个数据写入的操作,至于你想写入多少行数据,那就在后面继续写就行了,Add方法中的参数的个数就是你当前dt中的列数。dt.Rows.Add()里面的值之所以写死只不过是我没有从其他地方拿数据值,如果你的数据是动态的,那就定义几个变量,然后根据情况给变量赋值,再把变量按顺序传进来就行了。

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-21 12:50

@程序人生,永无止境: 好的,谢谢 !

差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-21 13:01

@程序人生,永无止境: dt.Rows.Add()这个方法里面的数据是动态,怎么定义几个变量啊?研究了1天了还是没研究出来额,麻烦帮贴点代码思路额、还有  if (dv[i]["名称"] == dv[i + 1]["名称"]) 这个比较我的怎么都跑不进去的....

差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-29 15:37

@差不哆丨好先生: 

 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是一样的,所以这个判断就会进去。

龙行天涯 | 园豆:1794 (小虾三级) | 2016-12-29 17:42
其他回答(3)
0

http://stackoverflow.com/questions/12278978/combining-n-datatables-into-a-single-datatable

Yu | 园豆:12980 (专家六级) | 2016-12-20 08:52

大哥,能否提供些详细的中文说明例子啊,英文实在是短板

支持(0) 反对(0) 差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-20 09:24
1
刘宏玺 | 园豆:14020 (专家六级) | 2016-12-20 09:11

还是不明白啊,大哥。能否提供个例子是返回datatable表的,而不是Console.WriteLine()方法返回的

支持(0) 反对(0) 差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-20 09:27

@差不哆丨好先生: 这个例子里的query.ToList()的结果就是一个DataRow的集合了

支持(0) 反对(0) 刘宏玺 | 园豆:14020 (专家六级) | 2016-12-20 09:29

@差不哆丨好先生: 这个写法挺好的 节省了很多代码。思路也清晰

支持(0) 反对(0) s_p | 园豆:138 (初学一级) | 2016-12-20 17:05
0

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);

        }
    }
}

园豆全是我的啦

需要格局 | 园豆:2145 (老鸟四级) | 2016-12-20 09:39

逗比,你仔细看下到底是不是人家要的结果

支持(0) 反对(1) ~扎克伯格 | 园豆:1923 (小虾三级) | 2016-12-20 14:28

谢谢大哥,辛苦啦,代码我还得研究下才能结帖额。

支持(0) 反对(0) 差不哆丨好先生 | 园豆:0 (初学一级) | 2016-12-20 22:08
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册