C# 从Csv文件中查找重复行的快速过程是什么?

C# 从Csv文件中查找重复行的快速过程是什么?,c#,asp.net,csv,C#,Asp.net,Csv,我有一个包含15,00000条记录的csv文件,需要从csv文件中找到重复的行。我正在尝试以下代码 DataTable dtUniqueDataView = dvDataView.ToTable(true, Utility.GetHeadersFromCsv(csvfilePath).Select(c => c.Trim()).ToArray()); 但在这方面,我没有得到重复的记录,这是采取了近4分钟的时间做手术。任何人都可以建议缩短时间并提供重复结果集的过程。不是最终解决方案,但可能

我有一个包含15,00000条记录的csv文件,需要从csv文件中找到重复的行。我正在尝试以下代码

DataTable dtUniqueDataView = dvDataView.ToTable(true, Utility.GetHeadersFromCsv(csvfilePath).Select(c => c.Trim()).ToArray());

但在这方面,我没有得到重复的记录,这是采取了近4分钟的时间做手术。任何人都可以建议缩短时间并提供重复结果集的过程。

不是最终解决方案,但可能需要从以下方面开始:

逐行读取CSV文件并计算每行的哈希值。您应该能够将这些数值保存在内存中

String.GetHashCode不够好,因为它可能会返回注释中正确指出的结果。需要更稳定的哈希算法

将它们存储在哈希集中,并检查其中是否已经存在该值。如果是,则可以跳过该行


注意:如果大部分时间都花在阅读上面评论中假设的文件上,那么您必须首先解决这个问题。我的假设是您担心找到重复项。

将csv文件作为流读取。一次只读一行。对于读取的每一行,计算MD5散列,并比较散列是否已经存在于您的存储中。如果是,则是重复的。

我用Hashset编写了一个示例:

在csv文件中输出15000000个条目: 读取文件 文件以16006632毫秒读取

在csv文件中输出30000000个条目: 读取文件 文件以31921997毫秒读取

在csv文件中输出45000000个条目: 读取文件 在49060755毫秒内读取文件


你能把整个文件保存在内存中吗?此外,如果读取文件需要4分钟,并且这段时间太长,无法找到副本,则重复查找代码不是您的问题,您需要找到更好/更快的方法来读取文件。是的,您是正确的。我已经尝试了所有的方法,但没有成功。尝试将大容量插入到SQL表中,然后运行Select语句以查找重复的。@highwingers您是正确的,但在此应用程序中没有DB调用。在哪台计算机上定义最快的?每行有多大?好奇-1-有什么评论吗?生日悖论。永远不要用哈希代码测试身份。您的算法几乎可以保证OP给定的数据集大小会发生哈希冲突。如果两个字符串对象相等,则GetHashCode方法返回相同的值。但是,对于每个唯一的字符串值,没有唯一的哈希代码值。不同的字符串可以返回相同的哈希代码。这个概念很好,但需要另一种算法来计算哈希值,以防止不正确的重复。还需要使用缓冲区读取文件,而不是逐行读取以提高性能。@Dubas你说得对!修改了我的答案-也许它仍然可以作为一个不同实现的开端。这个答案比@Krumelur的更糟糕。误解了散列是什么。加密散列的应用程序,其中一个简单的散列就可以了。这里的一个好处是散列更长。@Aron,虽然MD5算法不是无冲突的,也不能保证唯一性,但出于实际目的,这将满足Hermant的需要。它很独特。这就是为什么MD5和其他加密哈希可以用作消息摘要。我建议使用非加密哈希,例如。我发现这个解决方案真正有趣的是捕获哈希集的OOM并创建一个新的。有人可能认为OOM实际上意味着没有更多的内存,但在本例中,它只是意味着哈希集不能保存更多的数据。创意:-
class Program
{
    static void Main(string[] args)
    {
        string csvFile = "test.csv";
        if (!File.Exists(csvFile)) //Create a test CSV file
            CreateCSVFile(csvFile, 45000000, 15000);
        List<string> distinct = GetDistinct(csvFile); //Returns every line once

        Console.ReadKey();
    }
    static List<string> GetDistinct(string filename)
    {
        Stopwatch sw = new Stopwatch();//just a timer
        List<HashSet<string>> lines = new List<HashSet<string>>(); //Hashset is very fast in searching duplicates
        HashSet<string> current = new HashSet<string>(); //This hashset is used at the moment
        lines.Add(current); //Add the current Hashset to a list of hashsets
        sw.Restart(); //just a timer
        Console.WriteLine("Reading File"); //just an output message
        foreach (string line in File.ReadLines(filename))
        {
            try
            {
                if (lines.TrueForAll(hSet => !hSet.Contains(line))) //Look for an existing entry in one of the hashsets
                    current.Add(line); //If line not found, at the line to the current hashset
            }
            catch (OutOfMemoryException ex) //Hashset throws an Exception by ca 12,000,000 elements
            {
                current = new HashSet<string>() { line }; //The line could not added before, add the line to the new hashset
                lines.Add(current); //add the current hashset to the List of hashsets
            }
        }
        sw.Stop();//just a timer
        Console.WriteLine("File distinct read in " + sw.Elapsed.TotalMilliseconds + " ms");//just an output message
        List<string> concatinated = new List<string>(); //Create a list of strings out of the hashset list
        lines.ForEach(set => concatinated.AddRange(set)); //Fill the list of strings
        return concatinated; //Return the list
    }
    static void CreateCSVFile(string filename, int entries, int duplicateRow)
    {
        StringBuilder sb = new StringBuilder();
        using (FileStream fs = File.OpenWrite(filename))
        using (StreamWriter sw = new StreamWriter(fs))
        {
            Random r = new Random();
            string duplicateLine = null;
            string line = "";
            for (int i = 0; i < entries; i++)
            {
                line = r.Next(1, 10) + ";" + r.Next(11, 45) + ";" + r.Next(20, 500) + ";" + r.Next(2, 11) + ";" + r.Next(12, 46) + ";" + r.Next(21, 501);
                sw.WriteLine(line);
                if (i % duplicateRow == 0)
                {
                    if (duplicateLine != null && i < entries - 1)
                    {
                        sb.AppendLine(duplicateLine);
                        i++;
                    }
                    duplicateLine = line;
                }
            }
        }
    }
}