2011-03-11 56 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);