C# 从大型csv文件C.Net中删除重复记录

C# 从大型csv文件C.Net中删除重复记录,c#,.net,csv,C#,.net,Csv,我创建了一个解决方案,可以读取当前大小为20-30 mb的大型csv文件,我尝试根据用户在运行时使用查找重复行的常用技术选择的某些列值删除重复行,但速度太慢,以至于程序似乎根本无法运行 还有什么其他技术可以用于从csv文件中删除重复记录 这是密码,我肯定做错了什么 DataTable dtCSV = ReadCsv(file, columns); //columns is a list of string List column DataTable dt=RemoveDuplicateRecor

我创建了一个解决方案,可以读取当前大小为20-30 mb的大型csv文件,我尝试根据用户在运行时使用查找重复行的常用技术选择的某些列值删除重复行,但速度太慢,以至于程序似乎根本无法运行

还有什么其他技术可以用于从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; }
如果将排序例程实现为两个嵌套的for或foreach循环,则可以通过按要消除重复的列对数据进行排序,并将每一行与查看的最后一行进行比较来优化排序例程


不过,发布一些代码肯定是获得更好答案的好方法,如果你不知道如何实现它,你得到的任何东西都只是猜测。

你是否尝试过在类中包装行并使用Linq


Linq将为您提供获取不同值的选项等。

您当前正在为每一行创建一个字符串定义的筛选条件,然后对整个表运行该条件,这会很慢

最好采用Linq2Objects方法,将每一行依次读入一个类的实例,然后使用Linq Distinct操作符仅选择唯一的对象,非唯一对象将被丢弃

代码将类似于:

from row in inputCSV.rows
select row.Distinct()
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.
    }
}
如果您不知道CSV文件将包含哪些字段,那么您可能需要稍微修改这些字段-可能需要使用一个对象,将CSV单元格读入每行的列表或字典中


对于使用Linq从文件中读取对象,本文可能会有所帮助-

基于您在问题中包含的新代码,我将提供第二个答案-我仍然喜欢第一个答案,但如果您必须使用DataTable和DataRows,那么第二个答案可能会有所帮助:

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

一种方法是遍历该表,构建一个包含您感兴趣的组合列值的哈希集。如果您试图添加一个已经存在的字符串,那么您将有一个重复的行。比如:

from row in inputCSV.rows
select row.Distinct()
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.
    }
}

这应该是非常快的。

20-30MB太小,如果你做得正确,不会导致非常慢的速度,所以我认为你不是。分享一些代码。我看到你们捕捉到了异常,其中有多少发生了,它们可能是一个重大的减速!