C# 从Csv文件中查找重复行的快速过程是什么?
我有一个包含15,00000条记录的csv文件,需要从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分钟的时间做手术。任何人都可以建议缩短时间并提供重复结果集的过程。不是最终解决方案,但可能
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;
}
}
}
}
}