我有一个大约2000万行的文本文件。每行长度为25个字符。我估计大概有大约200k-300k的独特线路。我想知道的是究竟有多少条独特的线条,以及每条线条出现的次数(我希望结果是幂律式的)。
我可以这样做:
sort bigfile|uniq -c |sort -nr > uniqcounts
wc -l uniqcounts
但这是非常低效的记忆和时间。
这个问题的最佳命令行解决方案是什么?
答案 0 :(得分:6)
当我遇到像这样的文本处理问题时,我倾向于倾向于Perl,特别是因为Perl安装在大多数Unix系统上。 (你可以用awk做同样的事情,这可能会更有用。)
这样的事情可以解决问题:
#!/usr/bin/perl
while(<>) {
chomp;
$lines{$_}++;
}
print "Total unique lines: ", scalar(keys %lines), "\n";
foreach my $line (sort {$lines{$b} <=> $lines{$a}} keys %lines) {
printf "%6d %s\n", $lines{$line}, $line;
}
(你可以将其作为一个单行,但是分解使其更容易阅读。)
这需要O(n)内存用于散列键,其中 n 是唯一行的数量。运行时效率取决于散列查找,但介于O(n)(如果没有散列冲突)和O(n * log n)(对于平衡树)之间。在最坏的情况下,最终的可选排序可能需要O(n ^ 2),如果唯一行的数量很高,则可能在运行时占主导地位。
答案 1 :(得分:2)
我承担了被认为是偏离主题和被投票的风险,但我必须对此抱怨。
20百万* 25个字符= 500000000字节(假设您不是指Unicode)
这不到500 MB的RAM。对于现代计算机而言,这不是一个巨大的数字。
请不要抱怨这是非常低效的记忆和时间。将冗余数据存储在平面文本文件中的决定是低效且错误的。
使用数据库(例如sqlite)而不是平面文件。
使用类似
的表格CREATE TABLE lines (line VARCHAR(25), occurences INTEGER)
存储独特的线条及其出现。
如果不是您的应用程序生成此文本文件,请向开发人员抱怨它!
答案 2 :(得分:1)
确保在测试sort
和uniq
解决方案之前执行此操作:
export LC_ALL=C
如果你至少可以比较这个和perl解决方案的时间,那将是件好事。
答案 3 :(得分:1)
使用 awk (在 Solaris上使用 nawk 或 / usr / xpg4 / bin / awk :
awk 'END {
for (k in _)
print k, _[k]
}
{ _[$0]++ }
' infile
答案 4 :(得分:0)
我不确定是否有比您发布的解决方案更好的解决方案:O(n log(n)+ n)。鉴于问题陈述,你提到的精细的“sort -nr”并不是绝对必要的,但是使得输出更容易为人类所知。
如果有人能提出比这更快的解决方案(复杂性),我会非常感兴趣。当然,编写一个专用程序来做同样的事情可能比使用sort和uniq更快。