C# 保存行#以在满足条件时列出

C# 保存行#以在满足条件时列出,c#,C#,我有一个从csv导入的数据表。我要做的是将所有行相互比较,以找到重复的行。在重复的情况下,我将把行#添加到一个列表中,然后将列表写入一个数组,然后处理重复的行 //find duplicate rows and merge them. foreach (DataRow dr in dt.Rows) { //loop again to compare rows f

我有一个从csv导入的数据表。我要做的是将所有行相互比较,以找到重复的行。在重复的情况下,我将把行#添加到一个列表中,然后将列表写入一个数组,然后处理重复的行

            //find duplicate rows and merge them.
            foreach (DataRow dr in dt.Rows)
            {
                //loop again to compare rows
                foreach (DataRow dx in dt.Rows)
                {
                   if (dx[0]==dr[0] && dx[1]==dr[1] && dx[2] == dr[2] && dx[3] == dr[3] && dx[4] == dr[4] && dx[5] == dr[5] && dx[7] == dr[7])
                    {
                        dupeRows.Add(dx.ToString());
                    }
                }
            }
对于测试,我添加了:

listBox1.Items.AddRange(dupeRows.ToArray());
它只输出System.Data.DataRow


如何存储重复的行索引ID?

基本问题是,在确定行为重复行时,您保存了一个描述行类型的字符串(默认情况下DataRow.ToString()返回的内容)

假设您已使用某个库/驱动程序直接读取CSV,而不是逐行读取(这将是进行重复数据消除的好时机),让我们使用字典进行重复数据消除:

Dictionary<string, DataRow> d = new Dictionary<string, DataRow>();

foreach(var ro in dataTable.Rows){
  //form a key for the dictionary
  string key = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{7}", ro.ItemArray);

  d[key] = ro;
}
Dictionary d=newdictionary();
foreach(dataTable.Rows中的var ro){
//为字典编一个键
string key=string.Format(“{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{7}”,ro.ItemArray);
d[键]=ro;
}
就这样,;此操作结束时,
d.Values
将是重复数据行的集合。1000行将需要1000次操作,因此这可能比将每一行与每一行进行比较快几个数量级,而每1000行需要100万次操作

我在生成键时使用了制表符来分隔值——假设您的数据不包含制表符。如果您使用的字符未出现在数据中,则将实现最佳可靠性


如果您已经逐行读取CSV,并在逗号上手动拆分字符串(即读取CSV的原始方式),则可以执行此操作;分割后,可以使用一个数组来代替ro.ItemArray。处理整个文件,仅当
d.ContainsKey
返回false时才创建行(并添加到字典)。如果字典已经包含该行,请跳过而不是创建一行。基本问题是,在确定该行是重复行时,您保存了一个描述该行类型的字符串(默认情况下DataRow.ToString()返回的内容)

假设您已使用某个库/驱动程序直接读取CSV,而不是逐行读取(这将是进行重复数据消除的好时机),让我们使用字典进行重复数据消除:

Dictionary<string, DataRow> d = new Dictionary<string, DataRow>();

foreach(var ro in dataTable.Rows){
  //form a key for the dictionary
  string key = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{7}", ro.ItemArray);

  d[key] = ro;
}
Dictionary d=newdictionary();
foreach(dataTable.Rows中的var ro){
//为字典编一个键
string key=string.Format(“{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{7}”,ro.ItemArray);
d[键]=ro;
}
就这样,;此操作结束时,
d.Values
将是重复数据行的集合。1000行将需要1000次操作,因此这可能比将每一行与每一行进行比较快几个数量级,而每1000行需要100万次操作

我在生成键时使用了制表符来分隔值——假设您的数据不包含制表符。如果您使用的字符未出现在数据中,则将实现最佳可靠性

如果您已经逐行读取CSV,并在逗号上手动拆分字符串(即读取CSV的原始方式),则可以执行此操作;分割后,可以使用一个数组来代替ro.ItemArray。处理整个文件,仅当
d.ContainsKey
返回false时才创建行(并添加到字典)。如果字典已经包含该行,请跳过而不是创建一行,因为在项目中找不到DataRow.ToString()的自定义实现,所以您看到的输出(System.Data.DataRow)是预期的,框架正在调用基类(即System.Object)()默认实现返回调用该方法的对象的数据类型

我在这里看到三种解决方案:

  • 如果可能,尝试将DataTable读入自定义对象(如 MyDataTable,MyDataRow)这样,您就可以创建自己的ToString()了 下:
  • 在for循环中,当发现重复的行时,只需添加 将dx的索引/id(主键排序)添加到数组中,然后创建另一个 用于循环以检索重复项
  • 第三个和Caius Jard提到的一样
您看到的输出(System.Data.DataRow)是预期的,因为在您的项目中找不到DataRow.ToString()的自定义实现,框架正在调用基类(即System.Object)(),默认实现返回调用该方法的对象的数据类型

我在这里看到三种解决方案:

  • 如果可能,尝试将DataTable读入自定义对象(如 MyDataTable,MyDataRow)这样,您就可以创建自己的ToString()了 下:
  • 在for循环中,当发现重复的行时,只需添加 将dx的索引/id(主键排序)添加到数组中,然后创建另一个 用于循环以检索重复项
  • 第三个和Caius Jard提到的一样

顺便说一句,这真的很低效。构建字典会更有效如果您想按索引进行,请使用
for(int i=0;…
循环,而不是foreach。无论如何,最好避免双向比较,现在您将x与y进行比较,y与x进行比较,并且不必对ReferenceEquals(x,y)进行测试。因此,接下来会有很多事情。我的建议是,如果可能的话,不要将CSV读入数据表,而是将其读入强类型类。不要重新发明轮子,使用预构建的库,如。这样,您就可以轻松地使用LINQ检测重复项(或通过.Distinct消除重复项)。顺便说一句,这是非常低效的。构建字典会更有效。如果您想按索引进行,请使用
for(int i=0;…
循环,而不是foreach。无论如何,最好避免双向比较,现在您将x与y进行比较,y与x进行比较,并且不测试ReferenceEquals(x,y)。所以接下来会有很多事情。我的建议是,如果可能的话,不要将CSV读入数据表,并且