2011-03-11 76 views
3

我已经创建了一个解决方案,它读取当前大小为20-30 mb的大型csv文件,我试图根据用户选择的某些列值删除重复的行运行时间使用寻找重复行的常用技术,但速度太慢,看起来程序根本无法工作。从大csv文件删除重复的记录C#.Net

什么其他的技术可以被应用到从CSV文件

这里删除重复记录的代码,绝对是我做错了什么

 
DataTable dtCSV = ReadCsv(file, columns); 
//columns is a list of string List column 
DataTable dt=RemoveDuplicateRecords(dtCSV, columns); 

private DataTable RemoveDuplicateRecords(DataTable dtCSV, List<string> columns) 
     { 
      DataView dv = dtCSV.DefaultView; 
      string RowFilter=string.Empty; 

      if(dt==null) 
      dt = dv.ToTable().Clone(); 

      DataRow row = dtCSV.Rows[0]; 
      foreach (DataRow row in dtCSV.Rows) 
      { 
       try 
       { 
        RowFilter = string.Empty; 

        foreach (string column in columns) 
        { 
         string col = column; 
         RowFilter += "[" + col + "]" + "='" + row[col].ToString().Replace("'","''") + "' and "; 
        } 
        RowFilter = RowFilter.Substring(0, RowFilter.Length - 4); 
        dv.RowFilter = RowFilter; 
        DataRow dr = dt.NewRow(); 
        bool result = RowExists(dt, RowFilter); 
        if (!result) 
        { 
         dr.ItemArray = dv.ToTable().Rows[0].ItemArray; 
         dt.Rows.Add(dr); 

        } 

       } 
       catch (Exception ex) 
       { 
       } 
      } 
      return dt; 
     } 
+1

20-30 MB太小,如果你正确地做的话会导致某些东西非常慢,所以我假设你不是。分享一些代码。 – Jon 2011-03-11 11:50:19

+0

我看到你发现异常的事件有多少,他们可能是一个主要的放缓! – Peter 2011-03-11 12:02:24

+0

实际上现在没有例外 – Sandhurst 2011-03-11 12:05:08

回答

6

一种方式做,这是要经过台,建设HashSet<string>包含合并列值你感兴趣。如果你尝试添加一个字符串是al准备好了,那么你有一个重复的行。例如:

HashSet<string> ScannedRecords = new HashSet<string>(); 

foreach (var row in dtCSV.Rows) 
{ 
    // Build a string that contains the combined column values 
    StringBuilder sb = new StringBuilder(); 
    foreach (string col in columns) 
    { 
     sb.AppendFormat("[{0}={1}]", col, row[col].ToString()); 
    } 

    // Try to add the string to the HashSet. 
    // If Add returns false, then there is a prior record with the same values 
    if (!ScannedRecords.Add(sb.ToString()) 
    { 
     // This record is a duplicate. 
    } 
} 

这应该是非常快的。

+0

确实真的很快 – Sandhurst 2011-03-11 18:22:40

2

如果你实现了排序例程为一对夫妇嵌套的forforeach循环,您可以通过按希望去除重复的列对数据进行排序来优化它,并将每行与您查看的最后一行进行比较。

发布一些代码是一个可靠的方式来获得更好的答案,但没有一个你如何实现它的想法只会是猜测。

0

您是否尝试过使用Linq包装类中的行?

的LINQ会给你选择,让不同的值等

0

您目前正在制作的每行字符串定义的过滤条件,然后运行,对整个表 - 这将是缓慢的。

更好地采用Linq2Objects方法,将每行依次读入类的实例,然后使用Linq Distinct运算符仅选择唯一对象(非唯一对象将被丢弃)。

的代码看起来是这样的:

from row in inputCSV.rows 
select row.Distinct() 

如果你不知道你在CSV文件都将有那么字段,你可能需要修改此略有 - 可能使用的对象读取将CSV单元格转换为每行的列表或字典。

对于使用LINQ,这篇文章的人有或其他可能有助于从读取文件中的对象 - http://www.developerfusion.com/article/84468/linq-to-log-files/

0

根据您包含在你的问题的新的代码,我将提供第二个答案 - 我还是喜欢第一个答案,但如果你有使用DataTableDataRows,那么这第二个答案可能会帮助:

class DataRowEqualityComparer : IEqualityComparer<DataRow> 
{ 
    public bool Equals(DataRow x, DataRow y) 
    { 
     // perform cell-by-cell comparison here 
     return result; 
    } 

    public int GetHashCode(DataRow obj) 
    { 
     return base.GetHashCode(); 
    } 
} 

// ... 

var comparer = new DataRowEqualityComparer(); 
var filteredRows = from row in dtCSV.Rows 
        select row.Distinct(comparer);