如何在非常大的文本文件(~150 GB)中找到最大的数字?

How can I find the largest number in a very large text file (~150 GB)?

我有一个大约有 100000000 行的文本文件,每一行都属于以下类型:

string num1 num2 num3 ... num500
string num1 num2 num3 ... num40

我想找到此文件中存在的最大数字。

我当前的代码读取每一行,将其拆分为 space,并存储当前行中的最大数字。然后,我将它与下一行的最大数进行比较,并保留两者中较大的一个。

with open(filename,'r') as f:
    prev_max = -1
    for line in f:
        line = [int(n) for n in line.split(' ')[1:]]
        max = max_num(line)
        if max > prev_max:
            prev_max = max

但这需要永远。有更好的方法吗?

我也愿意接受使用 awk 或其他 shell 命令的解决方案。

编辑:添加了我阅读文件的方式。

这对于 awk 来说是一个微不足道的任务。

awk 'NR==1{m=} {for(i=2;i<=NF;++i) if(m<$i) m=$i} END{print m}' file

如果保证你的文件不全是零或负数,你可以去掉NR==1{m=}部分。

试试这个 Perl 解决方案

$ cat sample1.txt
string 1 2 4 10 7
string 1 2 44 10 7
string 3 2 4 10 70
string 9 2 44 10 7
$ perl -lane ' $m=(sort {$b<=>$a} @F[1..$#F])[0]; $max=$m>$max?$m:$max ; END { print $max } ' sample1.txt
70
$

我想编写一个没有 for 循环列的 awk 脚本,以将执行时间与 for 循环解决方案(例如 @oguzismail 的 琐碎的 进行比较。我创建了 1-100 列数据的一百万条记录,值在 0-2^32 之间。我玩 RS 只比较第 2-100 列,但由于需要正则表达式,它减慢了执行速度。很多。使用 tr 交换 space 和换行符我非常接近:

$ cat <(echo 0) file | tr ' \n' '\n ' | awk 'max<{max=}END{print max}'

cat <(echo 0) file | tr ' \n' '\n ' 的输出:

0 string1
1250117816
3632742839
172403688 string2
2746184479
...

使用的简单解决方案:

real    0m24.239s
user    0m23.992s
sys     0m0.236s

而我的 tr + awk 花费了:

real    0m28.798s
user    0m29.908s
sys     0m2.256s

(令人惊讶的是,如果我先用 tr 将数据预处理到一个文件中,然后用 awk 读取它,它不会更快,实际上大部分时间更慢)

所以,然后我决定测试我生疏的 C 技能来设置某种基准(手册页非常好。Google):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
  FILE * fp;
  char * line = NULL;
  char * word = NULL;
  size_t len = 0;
  ssize_t read;
  long max=0;
  long tmp=0;

  fp = fopen("file", "r");
  if (fp == NULL)
    exit(EXIT_FAILURE);
  while ((read = getline(&line, &len, fp)) != -1) {
    if((word = strtok(line," "))!=NULL) {
      while(word != NULL) {
        if((word = strtok(NULL," "))!=NULL) {
          tmp=strtol(word,NULL,10);
          if(max<tmp) {
            max=tmp;
          }
        }
      }
    }
  }
  fclose(fp);
  printf("%ld\n",max);
  exit(EXIT_SUCCESS);
}

结果:

$ time ./a.out 
4294967292

real    0m9.307s
user    0m9.144s
sys     0m0.164s

哦,用 mawk 代替 gawk 几乎减半了结果。