免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2147 | 回复: 5

一个文件处理问题如何用perl写出更短的代码解决 [复制链接]

论坛徽章:
0
发表于 2011-02-12 18:31 |显示全部楼层
test文件内容为:
aaa
001            123            728273
002            456            283940
003            789            928374
aaa
001            287            394872
003            729            493827
aaa
002            321            324815
bbb
003            524            520487
bbb
002            826            883674
003            673            092847
bbb
001            427            374859

要求分别得出aaa、bbb下001、002、003行中二列和三列的和,如:
aaa
001            410            1123145
002            777            608755
003            1518          1422201
bbb
001            427            374859
002            826            883674
003            1197          613334
这是shell版的一个问题,我自己想着用perl解决,但是写出来的代码感觉很搓,望高手能给出更短的代码解决这个问题。
下面是我自己瞎写的

  1. #!/usr/bin/perl
  2. use warnings;
  3. use strict;
  4. my %result;
  5. my $id1;
  6. while(<>){
  7.         my @temp=split;
  8.         my $id2;
  9.         if($#temp == 0){
  10.                 $id1=$temp[0];
  11.         } else {
  12.            $id2 = shift @temp;
  13.            unless(defined $result{$id1}{$id2})
  14.                 {
  15.                         $result{$id1}{$id2}=\@temp;
  16.                 }else{
  17.                         for(my $i=0;$i<=$#temp;$i++)
  18.                                 {
  19.                                         $result{$id1}{$id2}->[$i]+=$temp[$i];
  20.                                 }
  21.                 }


  22.         }
  23. }
  24. for my $i (sort keys %result){
  25.         print $i,"\n";
  26.         for my $j (sort { $a <=> $b } keys %{$result{$i}})
  27.         {
  28.                 print "$j\t",$result{$i}{$j}->[0],"\t",$result{$i}{$j}->[1],"\n";       }
  29. }
复制代码
希望高手们能帮我指出不规范的地方。。。谢谢了!

论坛徽章:
0
发表于 2011-02-12 18:40 |显示全部楼层
用hash啊

论坛徽章:
0
发表于 2011-02-12 18:42 |显示全部楼层
用hash啊
x9x9 发表于 2011-02-12 18:40



    我自己写的就是用hash的
    $VAR1 = {
          'bbb' => {
                     '002' => [
                                '826',
                                '883674'
                              ],
                     '003' => [
                                1197,
                                613334
                              ],
                     '001' => [
                                '427',
                                '374859'
                              ]
                   },
          'aaa' => {
                     '003' => [
                                1518,
                                1422201
                              ],
                     '002' => [
                                777,
                                608755
                              ],
                     '001' => [
                                410,
                                1123145
                              ]
                   }
        };

论坛徽章:
130
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
发表于 2011-02-12 22:59 |显示全部楼层
本帖最后由 jason680 于 2011-02-12 23:09 编辑
test文件内容为:
aaa
001            123            728273
002            456            283940
0 ...
zzy7186 发表于 2011-02-12 18:31
  1. #!/usr/bin/perl

  2. use strict;
  3. #基本上写程式不是问题,除错(debug)找问题才是问题....
  4. #所以code是不是(让人)易于了解才是要在意问题.
  5. #注:容易了解程式code,才容易"除错(debug)找问题"...

  6. #以下提供,我會用的方式.參考看看...
  7. my %ghResults;
  8. my $gsBlock;

  9. while(<DATA>){
  10.     next if(m/^\s*$/);  #处理空白行(非必要).... m/^\s*(#|$)/
  11.   
  12.     my($sId, @aTemp) = split;   #直接把id取出,不用再shift ...
  13.     if(@aTemp == 0){    # 或scalar @aTemp == 0, 少用$# 如果不是很必需
  14.         $gsBlock = $sId;
  15.         next;    #没有其他事要做...就直接next,
  16.         #可以省下else ...及不必要的缩进
  17.     }
  18.    
  19.   
  20.     #如果资料(数字)一定是二个....(含id 三个)
  21.     if(@aTemp != 2){
  22.         print "some error :$_\n";
  23.         #exit 1;   
  24.         # $error =1; next;
  25.     }
  26.   
  27.     #在这里defined ...的判断是不用的....
  28.     #if(defined $ghResults{$gsBlock}->{$sId}){
  29.         foreach(0 .. @aTemp -1){   #  $#aTemp
  30.             #print "get $aTemp[$_]\n";   # for debug
  31.             $ghResults{$gsBlock}->{$sId}->[$_] += $aTemp[$_];   
  32.         }
  33.     #}
  34.     #else{
  35.     #    # print "get @aTemp\n"; # for debug
  36.     #    $ghResults{$gsBlock}->{$sId} = [@aTemp];
  37.     #}
  38. }

  39. foreach my $sBlock(sort keys %ghResults){
  40.     local $" ="\t";  
  41.     print "$sBlock\n";
  42.     foreach(sort keys %{$ghResults{$sBlock}}){
  43.         # 简易输出... (設定local $")
  44.         #print "$_\t@{$ghResults{$sBlock}->{$_}}\n";
  45.         
  46.         # 数字对齐输出...
  47.         my $sOut = "";
  48.         $sOut .= sprintf("%12d",$_) for (@{$ghResults{$sBlock}->{$_}});
  49.         print "$_$sOut\n";
  50.     }
  51. }

  52. __DATA__
  53. aaa
  54. 001            123            728273
  55. 002            456            283940
  56. 003            789            928374
  57. aaa
  58. 001            287            394872
  59. 003            729            493827
  60. aaa
  61. 002            321            324815
  62. bbb
  63. 003            524            520487
  64. bbb
  65. 002            826            883674 22
  66. 003            673            092847
  67. bbb
  68. 001            427            374859
复制代码
perl block_array.pl
some error :002            826            883674 22

aaa
001         410     1123145
002         777      608755
003        1518     1422201
bbb
001         427      374859
002         826      883674          22
003        1197      613334

论坛徽章:
0
发表于 2011-02-13 08:57 |显示全部楼层
越写越复杂啊。个人觉得这样的问题也许是用一次就不会再用的脚本,或许不必写的如何通用。
  1. use strict;
  2. use warnings;

  3. my %hash;
  4. my $id;
  5. while (<DATA>) {
  6. chomp;
  7. if (/[^\d|\t|\s]/){
  8. $id=$_;
  9. } else {
  10. my ($x,$y,$z)=split;
  11. $hash{$id}{$x}{'col1'}+=$y;
  12. $hash{$id}{$x}{'col2'}+=$z;
  13. }
  14. }

  15. foreach my $k (sort keys %hash){
  16. print $k."\n";
  17. foreach my $kk (sort keys %{$hash{$k}}) {
  18. print $kk."\t".$hash{$k}{$kk}->{'col1'}."\t".$hash{$k}{$kk}->{'col2'}."\n";
  19. }
  20. }

  21. __DATA__
  22. aaa
  23. 001            123            728273
  24. 002            456            283940
  25. 003            789            928374
  26. aaa
  27. 001            287            394872
  28. 003            729            493827
  29. aaa
  30. 002            321            324815
  31. bbb
  32. 003            524            520487
  33. bbb
  34. 002            826            883674
  35. 003            673            092847
  36. bbb
  37. 001            427            374859
复制代码

论坛徽章:
0
发表于 2011-02-13 14:10 |显示全部楼层
本帖最后由 iLRainyday 于 2011-02-13 14:13 编辑

这个够不够短?最后的输出部分很丑~~
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. my $block_id;
  5. my %blocks;

  6. while (<DATA>) {
  7.     if (/^[a-z]/i) {
  8.         chomp;
  9.         $block_id = $_;
  10.     }
  11.     else {
  12.         my ($col_1, $col_2, $col_3) = split;
  13.         $blocks{$block_id}->{$col_1} =
  14.                        [ $blocks{$block_id}->{$col_1}[0] += $col_2,
  15.                          $blocks{$block_id}->{$col_1}[1] += $col_3 ];
  16.     }
  17. }

  18. for $block_id (keys %blocks) {
  19.     print "$block_id\n";
  20.     for my $key (keys %{ $blocks{$block_id} }) {
  21.         print "$key\t\t";
  22.         print "$blocks{$block_id}->{$key}[0]"
  23.               ."\t\t"
  24.               ."$blocks{$block_id}->{$key}[1]"
  25.               ."\n";
  26.      }
  27. }


  28. __DATA__
  29. aaa
  30. 001            123            728273
  31. 002            456            283940
  32. 003            789            928374
  33. aaa
  34. 001            287            394872
  35. 003            729            493827
  36. aaa
  37. 002            321            324815
  38. bbb
  39. 003            524            520487
  40. bbb
  41. 002            826            883674
  42. 003            673            092847
  43. bbb
  44. 001            427            374859
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

基于案例的 SQL 优化实战训练营

讲师:中电福富特级专家梁敬彬,参与本次课程培训,你将收获:
1. 能编写出较为高效的 SQL;
2. 能解决70%以上的数据库常见优化问题;
3. 能得到老师提供的高效的相关工具和解决方案;
4. 能举一反三,收获不仅仅是 SQL 优化。
现在购票享受8.8折优惠!
----------------------------------------
优惠时间:2019年3月20日前

大会官网>>
  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP