【发布时间】:2020-01-01 13:12:26
【问题描述】:
我有一个 C# 应用程序,除其他外,它需要删除重复的行,并将该行出现次数的计数附加到行的末尾。
文件可能非常大,从我的角度来看,我不能假设文件大小有任何限制。
对我来说,处理这个文件的最佳方式似乎是逐行处理。
删除重复项很好 - 我有以下内容(来自这个问题 Remove Duplicate Lines From Text File?):
using (TextReader reader = File.OpenText(newFilePath))
using (TextWriter writer = File.CreateText(aggregateFilePathBase))
{
string currentLine;
var previousLines = new HashSet<string>();
while ((currentLine = reader.ReadLine()) != null)
{
if (previousLines.Add(currentLine))
{
writer.WriteLine(currentLine);
}
else
duplicateArray.Add(currentLine);
}
}
我的问题是我可以轻松识别和删除重复项,但附加计数证明是有问题的。如您所见,我有一个数组,其中包含所有重复项的列表。然后我可以使用它来获取重复项并生成新行,如下所示:
if (duplicateArray.Count() > 0)
{
var duplicateGroups = duplicateArray.GroupBy(x => x);
foreach (var duplicate in duplicateGroups)
{
var duplicateCount = duplicate.Count() + 1;
var newLine = duplicate.First() + "," + duplicateCount;
}
}
问题是将计数写入文件。 我可以重新运行读/写过程,但我的问题是,基于对 150m 行文件的一些计算,此写入将需要 30 小时以上。所以在这种情况下,删除重复项需要 60 个小时。
谁能推荐一个更快的方法。
我假设将整个文件读入内存并进行查找和替换不是一种选择,因为文件太大而无法加载到内存中...
编辑: 从更多考虑这一点,我想我也可能会遇到 HashSet 的问题,因为这将有效地反映文件的大小,因此将限制为 2GB - 这是正确的吗?
【问题讨论】:
-
可能在创建期间将占位符计数“00000”写入文件,并记住该计数在文件中的位置,以便您可以返回并使用 Seek() 更新它。只要占位符计数有足够的位数来保存最大计数,它就应该起作用。如果需要,最终计数可以有前导零,或者您可以根据需要用空格覆盖额外的计数 - 但无论哪种方式,您都必须在更新时写入正确数量的字符。
-
基于 map/reduce 的方法怎么样?比如,将文件分成可消化的块并减少成对 [line, numberMatches]?
-
@Peter Duniho 你能告诉我你为什么搁置这个问题吗?在我看来,这个问题非常清楚。你能准确地告诉它有什么问题吗?
-
@EJoshuaS 你能告诉我你为什么搁置这个问题吗?在我看来,这个问题非常清楚。你能准确地告诉它有什么问题吗?
-
@Sangwin Gawande 你能告诉我你为什么搁置这个问题吗?在我看来,这个问题非常清楚。你能准确地告诉它有什么问题吗?