Iva*_*van 170 large-files text-processing files
我的一个巨大的(最多 2 GiB)文本文件包含其中每一行的大约 100 个精确副本(在我的情况下没用,因为该文件是一个类似 CSV 的数据表)。
我需要的是在保持原始序列顺序的同时删除所有重复(最好,但可以为了显着的性能提升而牺牲)。结果中的每一行都是唯一的。如果有 100 条相等的行(通常重复项分布在整个文件中并且不会是邻居),则只剩下一种。
我已经用 Scala 编写了一个程序(如果您不了解 Scala,请考虑使用 Java)来实现这一点。但也许有更快的 C 编写的本地工具能够更快地做到这一点?
更新:awk '!seen[$0]++' filename只要文件接近 2 GiB 或更小,该解决方案似乎对我来说很好用,但现在我要清理 8 GiB 文件,它不再起作用。在配备 4 GiB RAM 的 Mac 和配备 4 GiB RAM 和 6 GiB 交换的 64 位 Windows 7 PC 上,似乎无穷无尽,只是内存不足。鉴于这种经验,我并不热衷于在具有 4 GiB RAM 的 Linux 上尝试它。
enz*_*tib 276
awk在#bash (Freenode) 上看到的解决方案:
awk '!seen[$0]++' filename
Run Code Online (Sandbox Code Playgroud)
Gil*_*il' 52
有一种使用标准实用程序的简单(并不是说显而易见的)方法,除了 run 之外不需要大内存sort,在大多数实现中,它对大文件进行了特定优化(一个很好的外部排序算法)。这种方法的一个优点是它只循环特殊用途实用程序中的所有行,而不是在解释语言中。
<input nl -b a -s : | # number the lines
sort -t : -k 2 -u | # sort and uniquify ignoring the line numbers
sort -t : -k 1n | # sort according to the line numbers
cut -d : -f 2- >output # remove the line numbers
Run Code Online (Sandbox Code Playgroud)
如果所有行都以非空白字符开头,则可以省去一些选项:
<input nl | sort -k 2 -u | sort -k 1n | cut -f 2- >output
Run Code Online (Sandbox Code Playgroud)
对于大量重复,只需要在内存中存储每一行的单个副本的方法会表现得更好。有一些解释开销,有一个非常简洁的 awk 脚本(已由 enzotib 发布):
<input awk '!seen[$0]++'
Run Code Online (Sandbox Code Playgroud)
不那么简洁:!seen[$0] {print} {seen[$0] += 1},即如果还没有看到当前行,则打印当前行,然后增加seen该行的计数器(未初始化的变量或数组元素的数值为 0)。
对于长行,您可以通过仅保留每行的不可欺骗校验和(例如加密摘要)来节省内存。例如,使用 SHA-1,您只需要 20 个字节加上每行恒定的开销。但是计算摘要相当慢;只有当您有一个快速的 CPU(尤其是一个带有硬件加速器来计算摘要的 CPU)并且相对于文件的大小和足够长的行没有太多内存时,这种方法才会成功。没有基本的实用程序可以让您计算每一行的校验和;你必须承担 Perl/Python/Ruby/... 的解释开销,或者编写一个专门的编译程序。
<input perl -MDigest::MD5 -ne '$seen{Digest::MD5::md5($_)}++ or print' >output
Run Code Online (Sandbox Code Playgroud)
Vla*_*ecs 36
sort -u big-csv-file.csv > duplicates-removed.csv
Run Code Online (Sandbox Code Playgroud)
请注意,输出文件将被排序。
Mat*_*Mat 20
假设您有能力在内存中保留与重复数据删除文件一样多的内容(如果您的数据确实重复了 100 倍,那应该是大约 20MiB + 开销),您可以使用 Perl 轻松完成此操作。
$ perl -ne 'print unless $dup{$_}++;' input_file > output_file
Run Code Online (Sandbox Code Playgroud)
这也保留了顺序。
%dup如果您愿意,您可以从散列中提取每行出现的次数,作为额外的免费奖励。
如果您愿意awk,也应该这样做(与 perl 版本相同的逻辑、相同的顺序、在dup变量中收集的相同数据):
$ awk '{if (++dup[$0] == 1) print $0;}' input_file > output_file
Run Code Online (Sandbox Code Playgroud)
rin*_*eal 10
由于没有其他答案提供就地支持,这里是一个:
gawk -i inplace '!a[$0]++' file
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
230484 次 |
| 最近记录: |