【问题标题】:making arrays from tab-delimited text file column从制表符分隔的文本文件列制作数组
【发布时间】:2012-04-26 14:52:50
【问题描述】:

我想知道是否有人可以用 perl 帮助一个绝望的新手解决以下问题。我一整天都在尝试,但是我的 perl 书在工作,我似乎在谷歌中找不到任何相关的东西......或者也许我真的很愚蠢。

我有一个类似于以下内容的文件:

Bob     April
Bob     April
Bob     March
Mary    August
Robin   December
Robin   April

我要的输出文件是:

Bob     April April March
Mary    August
Robin   December April

这样它就会按照每个人出现的顺序列出每个月。

我尝试将其制成散列,但它当然不会让我有重复项,所以我想我想为每个名称(在本例中为 Bob、Mary 和 Robin)设置数组。 我害怕上传我一直在尝试调整的代码,因为我知道这将是非常错误的。我想我需要定义(?)数组。这是正确的吗?

任何帮助都将不胜感激,我保证在此期间我会更多地研究 perl。

感谢您的时间、耐心和帮助。

#!/usr/bin/perl -w

while (<>) {
    chomp;
    if (defined $old_name) {
        $name=$1;
        $month=$2;
        if ($name eq $old_name) { 
            $array{$month}++;   
            }
        else { 
            print "$old_name";
            foreach (@array)  { 
                push (@array, $month);
                print "\t@array";
                }
            print "\n";
            @array=(); 
            $array{$month}++; 
            }
        }
    else { 
        $name=$1;
        $month=$2;
        $array{month}++;
        }
    $old_name=$name; 
    }
print "$old_name"; 
foreach (@array)  {
    push (@array, $month);
    print "\t@array";
    }
print "\n";

【问题讨论】:

    标签: arrays perl parsing csv


    【解决方案1】:

    对于这样一个简单的任务,您的代码看起来过于复杂。

    use strict;
    use warnings;
    
    my %hash;
    while (<DATA>) {
        my ($name, $mon) = split;
        push @{$hash{$name}}, $mon;
    }
    
    for my $name (keys %hash) {
        my @months = @{$hash{$name}};
        print "$name\t@months\n";
    }    
    __DATA__
    Bob     April
    Bob     April
    Bob     March
    Mary    August
    Robin   December
    Robin   April
    

    【讨论】:

      【解决方案2】:

      你有点接近。您确实想使用名称作为键的散列,但如您所见,对于每个名称,您要存储一个 array 个月,因此您要使用的数据结构是散列数组(或者更确切地说是数组引用,因为这是在 Perl 中实现的)

      在此过程中,请不要养成使用全局变量的习惯 - 100% 的代码应该以“use strict; use warnings;”开头,并且是局部范围 (my) 变量。

      use strict;
      my %data;
      my @sorted_names; # Only needed if you care which order to print the results
      while (<>) {
          chomp;
          my ($name, $month) = split(/s+/);
          if (! $data{$name}) {
              # Initialize to empty array reference if first time. 
              # Not required - perl will do it for you
              $data{$name} ||= []; 
              # Only needed if you want to print results in the same order of names as input.
              push @sorted_names, $name;
          }
          push @{ $data{$name} }, $month;
      }
      
      foreach my $name (@sorted_names) {
          print "$name\t" . join(" ", @{ $data{$name} }) . "\n";
      }
      # If don't care about name order, just do "foreach my $name (keys %data) {"
      

      【讨论】:

      • 您不需要将标量值初始化为(空)数组 ref,它是自动完成的。
      • @TLP - 是的,但对于一个新手来说,这有点不直观。
      【解决方案3】:

      脚本:

      #!/usr/bin/perl
      use strict;
      use warnings;
      
      my %content;
      open my $fh, '<file.txt' or die $!;
      while (<$fh>) {
        push @{$content{$1}}, $2 if /^(\S+)\s+(\S+)\s*$/;
      }
      close $fh;
      foreach (keys %content) {
        print $_, "\t";
        foreach my $item (@{$content{$_}}) {
          print "$item ";
        }
        print "\n";
      }
      

      #!/usr/bin/perl
      use strict;
      use warnings;
      
      my %content;
      open my $fh, '<file.txt' or die $!;
      while (<$fh>) {
        push @{$content{$1}}, $2 if /^(\S+)\s+(\S+)\s*$/;
      }
      close $fh;
      print "$_\t@{$content{$_}}\n" for keys %content;
      

      #!/usr/bin/perl
      use strict;
      use warnings;
      
      my %content;
      open my $fh, '<file.txt' or die $!;
      s/^(\S+)\s+(\S+)\s*$/{push @{$content{$1}}, $2}/e for <$fh>;
      close $fh;
      print "$_\t@{$content{$_}}\n" for keys %content;
      

      输出:

      Bob     April April March 
      Mary    August 
      Robin   December April 
      

      对于带有内容的文件file.txt

      Bob     April
      Bob     April
      Bob     March
      Mary    August
      Robin   December
      Robin   April
      

      【讨论】:

        【解决方案4】:

        一个简单的方法是使用 perl 的 push 和 pop 函数。(因为你开始使用 perl:http://perldoc.perl.org/functions/pop.htmlhttp://perldoc.perl.org/functions/push.html) 您应该为每个名称(例如@bobmonths)保留一个全局数组,并在每次找到一个时推送一个月。 完成后,打印出名称和数组:

        while(<>)
        {
        chomp;
        push(@bobmonths, $2)
        
        ...
        }
        print @bobmonths
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-02
          • 1970-01-01
          • 1970-01-01
          • 2010-09-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多