免费注册 查看新帖 |

Chinaunix

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

请教perl循环问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-03 14:41 |只看该作者 |倒序浏览
两个文件
第一个文件两列,每行的两列数字构成一个区间,
11    20
30    50
等等
另外一个是一列数字,
类似,
12
15
30
45
50

等等

问题是想统计一下第2个文件中落在第一个文件中的数字的个数,例如,12落在了11    20之间,那么$hash{11    20}++一次,最后输出第一文件每行出现的次数。
关键的问题是每个文件都好几万行,循环起来比较慢,我想请教大家有什么好的建议,谢谢

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
2 [报告]
发表于 2010-11-03 14:43 |只看该作者
本帖最后由 zhlong8 于 2010-11-03 14:49 编辑

第一个文件的数字区间有交集没有? 总的范围有多大? 全都是整数吗? 闭区间还是左开右闭什么的?

所有区间范围小的话可以用list的index做键

比如建立个list

list:
[0][1][2]...[n]
      
第二个文件按你的规则把相当位的值加一,最后再读第一个文件,分析每个区间的数字个数

论坛徽章:
0
3 [报告]
发表于 2010-11-03 14:51 |只看该作者
回复 2# zhlong8

没有交集,总的范围不固定,最多上千,都是整数,都是闭区间

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
4 [报告]
发表于 2010-11-03 14:57 |只看该作者
本帖最后由 zhlong8 于 2010-11-03 15:09 编辑

没测试数据,你看下思路
  1. use strict;
  2. use warnings;
  3. my @info;
  4. my %result;    #保存结果的hash
  5. sub sum_from;


  6. open my $f, '<', 'file2' or die $!;

  7. while (<$f>) {    #假定file2里面的数据都是自然数
  8.     chomp;
  9.     $info[$_]++;  #因为最多上千,所以不会产生超大的array
  10. }

  11. close $f;

  12. open $f, '<', 'file1' or die $!;

  13. while (<$f>) {
  14.     chomp;
  15.     my($from, $to) = split /\s+/;
  16.     $result{"$from $to"} = sum_from $from, $to;
  17. }


  18. sub sum_from {
  19.     my($from, $to) = @_;
  20.     my $sum = 0;
  21.     $sum += $info[$_]//0 for $from .. $to; # // 消除uninitialized value 警告
  22.     return $sum;
  23. }
复制代码

论坛徽章:
0
5 [报告]
发表于 2010-11-03 15:00 |只看该作者
回复 4# zhlong8


    3x,我试试阿

论坛徽章:
0
6 [报告]
发表于 2010-11-03 15:33 |只看该作者
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;
  4. my @info;

  5. open my $f, '<', 'file2.txt' or die $!;
  6. while (<$f>) {    #假定file2里面的数据都是自然数
  7.     chomp;
  8.     $info[$_]++;
  9. }
  10. close $f;

  11. open $f, '<', 'file1.txt' or die $!;
  12. while (<$f>) {
  13.     chomp;
  14.     my($from, $to) = split /\s+/;
  15.     my $count;
  16.     for ($from..$to) {
  17.             $count++ if ($info[$_]);
  18.     }
  19.     print "$from $to $count\n";
  20. }
  21. close $f;

  22. <STDIN>;
复制代码
4楼的代码运行起来应该非常快,学习了。

为了更少占用内存,可以统计一个区间后马上输出,不存入%result,因为文件1还是比较大的。

说明:
假设file2里面的数据都是自然数;
若文件1的各区间有交集,4楼的程序也适用。

论坛徽章:
0
7 [报告]
发表于 2010-11-03 15:33 |只看该作者
回复 2# zhlong8


谢谢   zhlong8,确实好使!!!
我还有一个问题想请教,就是:如果第2个文件如果也是两列,其它的不变,也就是说第2个文件的这两个数都在第一个数的某个区间内,该怎么写???谢谢

论坛徽章:
7
巳蛇
日期:2014-04-10 08:54:57白羊座
日期:2014-04-22 20:06:262015年亚洲杯之沙特阿拉伯
日期:2015-02-10 14:18:532015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之吉达阿赫利
日期:2015-06-02 11:34:112015亚冠之武里南联
日期:2015-06-24 12:13:082015亚冠之阿尔纳斯尔
日期:2015-08-03 09:08:25
8 [报告]
发表于 2010-11-03 15:47 |只看该作者
回复 7# liuguiyou1981
如果是排好序的,这个还是比较容易实现的。如果不是排好序的,或许先排序是个好主意。

论坛徽章:
46
15-16赛季CBA联赛之四川
日期:2018-03-27 11:59:132015年亚洲杯之沙特阿拉伯
日期:2015-04-11 17:31:45天蝎座
日期:2015-03-25 16:56:49双鱼座
日期:2015-03-25 16:56:30摩羯座
日期:2015-03-25 16:56:09巳蛇
日期:2015-03-25 16:55:30卯兔
日期:2015-03-25 16:54:29子鼠
日期:2015-03-25 16:53:59申猴
日期:2015-03-25 16:53:29寅虎
日期:2015-03-25 16:52:29羊年新春福章
日期:2015-03-25 16:51:212015亚冠之布里斯班狮吼
日期:2015-07-13 10:44:56
9 [报告]
发表于 2010-11-03 15:51 |只看该作者
本帖最后由 zhlong8 于 2010-11-03 15:52 编辑

回复 7# liuguiyou1981


    类似不过要多点处理。再写下:)
  1. use strict;
  2. use warnings;

  3. my @info;
  4. my %result;
  5. sub sum_from;


  6. open my $f, '<', 'file2' or die $!;

  7. while (<$f>) {
  8.     chomp;
  9.     my($from, $to) = split /\s+/;
  10.     push @{$info[$from]}, $.;
  11.     push @{$info[$to]}, $.;    #$. 为第二个文件每个区间的 unique ID
  12. }

  13. close $f;

  14. open $f, '<', 'file1' or die $!;

  15. while (<$f>) {
  16.     chomp;
  17.     my($from, $to) = split /\s/;
  18.     $result{"$from $to"} = sum_of $from, $to;
  19. }

  20. sub sum_from {      #任何ID在这个区间出现两次即说明整个file2的区间就在其中
  21.     my($from, $to) = @_;
  22.     my $sum;

  23.     my %dict;
  24.     for my $entry ($from .. $to) {
  25.         $dict{$_} ++ for @{$info[$entry]}; #以上面的unique ID 为键
  26.     }
  27.     #所有值为2的entry即为答案,计算总数即可

  28.     while (my($k,$v) = each %dict) {
  29.         $sum ++ if $v == 2;
  30.     }
  31.     return $sum;
  32.             
  33. }
复制代码

论坛徽章:
0
10 [报告]
发表于 2010-11-03 15:51 |只看该作者
回复 8# Monox


   恩  那就当排好序了,呵呵 这样容易实现些,对了,还有 刚才程序中的子程序我没看明白,你能解释下么?谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP