python-3.x 如何在一个非常大的文本文件(~150 GB)中找到最大的数字?

kkih6yb8  于 2022-12-15  发布在  Python
关注(0)|答案(4)|浏览(133)

我有一个文本文件,大约有100000000行,每一行的类型如下:

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

我想找到这个文件中出现的最大数字。
我当前的代码读取每一行,用空格将其拆分,并将最大的数字存储在当前行中,然后将其与下一行的最大数字进行比较,并保留两者中较大的一个。

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命令的解决方案也持开放态度。
编辑:添加了我如何阅读文件。

l7mqbcuq

l7mqbcuq1#

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

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

如果可以保证文件不全是零或负数,则可以删除NR==1{m=$2}部分。

uajslkp6

uajslkp62#

试试这个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
$
hfyxw5xn

hfyxw5xn3#

我想编写一个awk脚本,但不使用for循环列,以便与for循环解决方案(如@oguzismail的 trivial)比较执行时间。值在0-2^32之间。我尝试使用RS只比较列2-100,但由于这需要正则表达式,它降低了执行速度。使用tr来交换空间和换行符,我已经非常接近了:

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

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

0 string1
1250117816
3632742839
172403688 string2
2746184479
...

使用的 trivial 解决方案:

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

而我的tr + awk花费了:

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

(令人惊讶的是,如果我先用tr将数据预处理成一个文件,然后用awk读取它,它不会更快,实际上大多数时候会更慢)
所以,我决定测试一下我生疏的C语言技能,以设定某种基准(手册页相当不错,还有谷歌):

#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,结果几乎减半。

cbeh67ev

cbeh67ev4#

您不需要CC++来提高速度-awk有很多优点:
我创建了一个957 MB合成文件,其中包含02^48 - 1之间的随机整数,
加上擦除所有偶数位的尾部(以减少但不消除由于rand()本身均匀分布而导致的十进制#位分布朝向高侧的聚集效应):
-- * 这也意味着真正的最小值是1,而不是0 *

# rows  | # of decimal digits

           5 1
          45 2
         450 3
       4,318 4
      22,997 5
      75,739 6
     182,844 7
     382,657 8
     772,954 9
   1,545,238 10
   3,093,134 11
   6,170,543 12
  12,111,819 13
  22,079,973 14
  22,204,710 15

...而awk只需**6.28 secs扫描68.6 mn rows**(70 mn重复数据消除前)即可找到最大的::
一个一个一个一个一个x一个一个二个一个x一个一个三个一个x一个一个x一个四个一个
在这样的吞吐率下,与单个awk示例相比,使用类似gnu-parallel的示例可能只能产生很小的增益。

相关问题