从制表符分隔的文本文件列创建数组

时间:2012-04-14 14:40:20

标签: arrays perl parsing tab-delimited-text

我想知道是否有人可以通过以下问题帮助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";

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

你有点亲近。您确实希望使用名称为键的哈希,但正如您所看到的,对于每个名称,您要存储数组的月份,因此您要使用的数据结构是哈希数组(或者更确切地说是数组引用,因为这是在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) {"

答案 2 :(得分:1)

<强> 脚本:

#!/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

答案 3 :(得分:0)

一种简单的方法是使用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