将整个文件读入Perl中的哈希

时间:2011-09-30 12:36:04

标签: perl hash

我在Perl中将文件读入哈希时遇到了一些问题。

Chr1_supercontig_000000000  1   500
    PILOT21_588_1_3_14602_59349_1
Chr1_supercontig_000000001  5   100
    PILOT21_588_1_21_7318_90709_1
    PILOT21_588_1_43_18803_144592_1
    PILOT21_588_1_67_13829_193943_1
    PILOT21_588_1_42_19678_132419_1
    PILOT21_588_1_67_4757_125247_1
...

所以我上面有这个文件。我想要的输出是一个散列,其中" Chr1" -lines为键," PILOT" -lines为值。

Chr1_supercontig_000000000 => PILOT21_588_1_3_14602_59349_1
Chr1_supercontig_000000001 => PILOT21_588_1_21_7318_90709_1, PILOT21_588_1_43_18803_144592_1,...

据我所知,只能通过引用将多个值分配给一个键,这是正确的吗?

我在这一点上陷入困​​境并需要帮助。

6 个答案:

答案 0 :(得分:5)

你是对的,哈希值需要是指向包含PILOT行的数组的引用。

这是一种方法:

my %hash;
open FILE, "filename.txt" or die $!;
my $key;
while (my $line = <FILE>) {
     chomp($line);
     if ($line !~ /^\s/) {
        ($key) = $line =~ /^\S+/g;
        $hash{$key} = [];
     } else {
        $line =~ s/^\s+//;
        push @{ $hash{$key} }, $line;
     }
 }
 close FILE;

答案 1 :(得分:5)

您可以逐行读取文件,跟踪当前的哈希键:

open my $fh, '<', 'file' or die $!;

my (%hash, $current_key);

while (<$fh>) {
    chomp;        
    $current_key = $1, next if /^(\S+)/;
    s/^\s+//; # remove leading space
    push @{ $hash{$current_key} }, $_;
}

答案 2 :(得分:2)

怎么样:

#!/usr/bin/perl 
use strict;
use warnings;
use Data::Dump qw(dump);

my %hash;
my $key;
while(<DATA>) {
    chomp;
    if (/^(Chr1_supercontig_\d+)/) {
        $key = $1;
        $hash{$key} = ();
    } else {
        push @{$hash{$key}}, $_;
    }
}
dump%hash;

__DATA__
Chr1_supercontig_000000000  1   500
    PILOT21_588_1_3_14602_59349_1
Chr1_supercontig_000000001  5   100
    PILOT21_588_1_21_7318_90709_1
    PILOT21_588_1_43_18803_144592_1
    PILOT21_588_1_67_13829_193943_1
    PILOT21_588_1_42_19678_132419_1
    PILOT21_588_1_67_4757_125247_1

<强>输出:

(
  "Chr1_supercontig_000000001",
  [
    "    PILOT21_588_1_21_7318_90709_1",
    "    PILOT21_588_1_43_18803_144592_1",
    "    PILOT21_588_1_67_13829_193943_1",
    "    PILOT21_588_1_42_19678_132419_1",
    "    PILOT21_588_1_67_4757_125247_1",
  ],
  "Chr1_supercontig_000000000",
  ["    PILOT21_588_1_3_14602_59349_1"],
)

答案 3 :(得分:2)

许多好的答案已经存在,所以我将添加一个不依赖于正则表达式的答案,而是根据关键字线包含三个空格/制表符分隔的条目,并且值只有一个。

它会自动删除前导空格和换行符,因此有点方便。

use strict;
use warnings;

my %hash;
my $key;

while (<DATA>) {
    my @row = split;
    if (@row > 1) {
        $key = shift @row;
    } else {
        push @{$hash{$key}}, shift @row;
    }
}

use Data::Dumper;
print Dumper \%hash;

__DATA__
Chr1_supercontig_000000000  1   500
    PILOT21_588_1_3_14602_59349_1
Chr1_supercontig_000000001  5   100
    PILOT21_588_1_21_7318_90709_1
    PILOT21_588_1_43_18803_144592_1
    PILOT21_588_1_67_13829_193943_1
    PILOT21_588_1_42_19678_132419_1
    PILOT21_588_1_67_4757_125247_1

答案 4 :(得分:1)

这是另一个相当简短的版本:

while (<>) {
   if(/^Chr\S+/) {
      $c=$&;
   } else {
      /\S+/;
      push @{ $p{$c} }, $&;
   }
}

打印结果:

foreach my $pc ( sort keys %p ) {
   print "$pc => ".join(", ", @{$p{$pc}})."\n";
}

这是一个较短的打印结果(但第一个看起来对我来说更具可读性):

map { print "$_ => ".join(", ", @{$p{$_}})."\n" } sort keys %p;

命令行中的单行:

perl <1 -e 'while(<>){ if(/^Chr\S+/){ $c=$&; }else{ /\S+/; push(@{$p{$c}},$&);} } map { print "$_ => ".join(", ", @{$p{$_}})."\n" } sort keys %p;'

答案 5 :(得分:0)

试试这个,

#!/usr/bin/perl 
use strict;
use warnings;
use Data::Dumper;

my ( $fh,$cur );
my $hash = ();
open $fh,'<' , 'file' or die "Can not open file\n";

while (<$fh> ) {
    chomp;
    if ( /^(Chr.+? ).+/ ) {
        $cur = $1;
        $hash->{$cur} = '';
    }
    else {
        $hash->{$cur} = $hash->{$cur} .$_ . ',';
    }
}

print Dumper $ hash;