免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 6876 | 回复: 25
打印 上一主题 下一主题

关于从两个文件中提取需要的行,大家帮我看看为啥我的脚本执行效率超低 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-05-21 17:26 |只看该作者 |倒序浏览
本帖最后由 kidaaaa 于 2010-05-21 18:09 编辑

我有两个文件,都是列表形式的数据
现在需要:  当:文件1的第一列与文件2的第二列相同,且文件1的第二列小于等于文件2的第九列,且文件1的第三列大于等于文件2的第十列,
则合并输出这两行。

我的代码如下:
  1.   1 #!/usr/bin/perl
  2.   2
  3.   3 open PTT, "file1"
  4.   4 or die 'Can not open the required file file1 !';
  5.   5 open BR, "file2"
  6.   6 or die 'Can not open the required file file2 !';
  7.   7 @PTT = <PTT>;
  8.   8 @BR = <BR>;
  9.   9 close PTT;
  10. 10 close BR;
  11. 11
  12. 12 foreach $BR_line (@BR)
  13. 13 {
  14. 14     foreach $PTT_line (@PTT)
  15. 15     {
  16. 16         @ptt = split /\s+/, $PTT_line;
  17. 17         
  18. 18         @br = split /\s+/, $BR_line;
  19. 19         
  20. 20         if(($ptt[0] eq $br[1]) and ($br[8] >= $ptt[1]) and ($br[9] <= $ptt[2]))
  21. 21         {
  22. 22             chomp $BR_line ;
  23. 23             print $BR_line , '    ', $PTT_line ;
  24. 24         }   
  25. 25     }
  26. 26 }
复制代码
本人初学perl,大家轻拍。
由于我这两个文件数据量都很大一个有几百万行,一个有几千万行,所以要求执行效率很高才行,求高手们帮忙。

论坛徽章:
78
双子座
日期:2013-10-15 08:50:09天秤座
日期:2013-10-16 18:02:08白羊座
日期:2013-10-18 13:35:33天蝎座
日期:2013-10-18 13:37:06狮子座
日期:2013-10-18 13:40:31双子座
日期:2013-10-22 13:58:42戌狗
日期:2013-10-22 18:50:04CU十二周年纪念徽章
日期:2013-10-24 15:41:34巨蟹座
日期:2013-10-24 17:14:56处女座
日期:2013-10-24 17:15:30双子座
日期:2013-10-25 13:49:39午马
日期:2013-10-28 15:02:15
2 [报告]
发表于 2010-05-21 17:50 |只看该作者
两个文件多大呢?

论坛徽章:
0
3 [报告]
发表于 2010-05-21 18:15 |只看该作者
回复 2# yybmsrs


    两个都是三四百兆大小,一个几百万行,一个一千多万行。数据量比较大,求教高效率处理方法,谢谢~~

论坛徽章:
78
双子座
日期:2013-10-15 08:50:09天秤座
日期:2013-10-16 18:02:08白羊座
日期:2013-10-18 13:35:33天蝎座
日期:2013-10-18 13:37:06狮子座
日期:2013-10-18 13:40:31双子座
日期:2013-10-22 13:58:42戌狗
日期:2013-10-22 18:50:04CU十二周年纪念徽章
日期:2013-10-24 15:41:34巨蟹座
日期:2013-10-24 17:14:56处女座
日期:2013-10-24 17:15:30双子座
日期:2013-10-25 13:49:39午马
日期:2013-10-28 15:02:15
4 [报告]
发表于 2010-05-21 18:21 |只看该作者
用数据库

论坛徽章:
0
5 [报告]
发表于 2010-05-22 01:46 |只看该作者
本帖最后由 iamlimeng 于 2010-05-22 01:54 编辑

象你这样,一次性读入内存,很容易将内存资源消耗完而当机。应该一行一行读入,然后判断。以下代码仅供参考,我想运行时间还是会很长,但比你的效率要高很多:
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. open BR, "file2" or die 'Can not open the required file file2 !';
  5. while (my $BR_line = <BR>) {
  6.          my @br = split /\s+/, $BR_line;
  7.         open PTT, "file1" or die 'Can not open the required file file1 !';
  8.         while (my $PTT_line = <PTT>) {
  9.                  my @ptt = split /\s+/, $PTT_line;
  10.                  if(($ptt[0] eq $br[1]) and ($br[8] >= $ptt[1]) and ($br[9] <= $ptt[2]))
  11.                  {
  12.                          chomp $BR_line;
  13.                          print $BR_line , '    ', $PTT_line;
  14.                  }
  15.          }
  16.         close PTT;
  17. }
  18. close BR;
复制代码

论坛徽章:
0
6 [报告]
发表于 2010-05-22 04:11 |只看该作者
四楼能具体说说用数据库处理这类问题效率真的可以很高吗?我已经试过用mysql来处理了,好像也不快,运行了几天也没得到输出,不知是mysql数据库处理超大数据量时效率低下的问题还是什么?用PostgreSQL会快很多吗?

谢谢五楼的帮助,我用的是32G内存的小型服务器,内存占用问题并不是问题,我要求关键还是脚本的处理速度要快。你的代码我试了试和我原来的代码执行速度基本相当,不过还是非常感谢~~~

论坛徽章:
0
7 [报告]
发表于 2010-05-22 10:19 |只看该作者
本帖最后由 iamlimeng 于 2010-05-22 10:20 编辑

原以为楼主是在个人计算机上跑,那内存就会被撑暴。

数据库能提高效率,是因为它有针对性地对需要重复查询的数据进行了优化,在没有优化情况下,效率也高不到哪去。要提高效率,一方面应该尽量减少重复计算次数(你的计算量本来就很大,几百万*几千万),一方面还是要尽量减少内存占用(虽然你的内存很大)。如果使用二维数组,并将file1数据一次性构造好,能减少一些计算,效率会得到一定的提高,不过不要期待太高。以下经优化的代码供参考:
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. my @ptt_new;
  5. open PTT, "file1" or die 'Can not open the required file file1 !';
  6. while (my $PTT_line = <PTT>)
  7. {
  8.         my @ptt = split /\s+/, $PTT_line;
  9.         push(@ptt_new,[@ptt]);
  10. }
  11. close PTT;

  12. open BR, "file2" or die 'Can not open the required file file2 !';
  13. while (my $BR_line = <BR>)
  14. {
  15.         my @br = split /\s+/, $BR_line;
  16.         for (0..$#ptt_new)
  17.         {
  18.                  if($ptt_new[$_][0] eq $br[1] and $br[8] >= $ptt_new[$_][1] and $br[9] <= $ptt_new[$_][2])
  19.                  {
  20.                          chomp $BR_line ;
  21.                          print $BR_line , '    ', join(' ',$ptt_new[$_]);
  22.                  }
  23.         }
  24. }
  25. close BR;
复制代码

论坛徽章:
0
8 [报告]
发表于 2010-05-22 11:24 |只看该作者
本帖最后由 hu145165 于 2010-05-22 11:34 编辑

LZ 你的文件行数既然不是同一个数量级,又怎么进行比较呢?
文件1的第一列与文件2的第二列相同,且文件1的第二列小于等于文件2的第九列,且文件1的第三列大于等于文件2的第十列,
则合并输出这两行。
既然文件1 的第一列 和文件文件2的第二列相同,为什么不用hash 将相同的一列当为key 来存相同列的行数据
再进行比较?
这样效率就明显要比你高得多,如果像你那样,每一行都要历遍一次文件,效率是可想而知的。
结构可以这样定义:
my %hash;
$hasn{$clumn} = [[split /\s+/,$row1],[split /\s+/,$row2],.....];
乍样要比你效率快多了

论坛徽章:
0
9 [报告]
发表于 2010-05-22 11:39 |只看该作者
回复 8# hu145165

我开始也是这样想,但认真看了楼主的代码,应该不是那回事。

它是以file2每一行为判断依据,只要file1的每行数据满足条件,就输出,所以不是你想象的那样。这样的计算量确实非常大,也很耗时。

论坛徽章:
1
未羊
日期:2014-09-08 22:47:27
10 [报告]
发表于 2010-05-22 11:58 |只看该作者
本帖最后由 wxlfh 于 2010-05-22 12:02 编辑

既然文件1和文件2的行数不一样,那么我可以猜想文件1的第一列肯定是唯一的,否则你的比较就没有意义了。那么,可以把文件1的第一列当散列的关键字,文件2的第2列在散列里查找是否有这个关键字。
  1. use strict;

  2. my %file1;

  3. open my $fh1,"<","file1.txt" or die "Open file1.txt failed.\n";
  4. while (<$fh1>) {
  5.     chomp;
  6.     my @tmp = split /\s+/;
  7.     $file1{$tmp[0]} = [@tmp[1..$#tmp]];
  8. }
  9. close $fh1;

  10. open my $fh2,"<","file2.txt" or die "Open file2.txt failed.\n";
  11. open my $out,">","file3.txt" or die "Create file3.txt failed.\n";
  12. while (<$fh2>) {
  13.     chomp;
  14.     my @tmp = split /\s+/;
  15.     my $key = $tmp[1];
  16.     if (exist $file1{$key}) {
  17.         next if not ($file1{$key}->[0] <= $tmp[8]
  18.                 and $file1{$key}->[1] >= $tmp[9]);
  19.         my @str = ($key,@{$file1{$key}},@tmp[0,2..$#tmp],"\n");
  20.         print $out "@str";
  21.     }else {
  22.         next;
  23.     }
  24. }
  25. close $fh2;
  26. close $out;
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP