【问题标题】:Reading an entire file into a hash in Perl在 Perl 中将整个文件读入哈希
【发布时间】:2017-02-19 14:49:44
【问题描述】:

我在 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”行作为键,“PILOT”行作为值的散列。

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,...

据我所知,多个值只能通过引用分配给一个键,对吗?

我被困在这一点上,需要帮助。

【问题讨论】:

    标签: perl hash


    【解决方案1】:

    你是对的,哈希值需要是指向包含 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;
    

    【讨论】:

    • 您可能想在第一个 \s 处删除 $key 以获得 'Chr1_supercontig_000000000' 而不是 'Chr1_supercontig_000000000 1 500'
    • 感谢您的快速回复。还没有尝试过,但现在会做!您在 if 子句中使用的正则表达式正在查找不以空格开头的行?
    • 没错,菲利普。另请注意,我已经更新了代码,因此请使用您现在看到的代码。
    • if ($line =~ /^(\S+)/) { $key = $1; ... 为您节省了一行代码。而且你不需要预先定义$hash{$key}
    【解决方案2】:

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

    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} }, $_;
    }
    

    【讨论】:

    • 谢谢,我也试过了,效果很好!清晰清晰 =)
    • push @{$hash{$current_key}}, split 会为您节省 chomps/s+//
    【解决方案3】:

    怎么样:

    #!/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"],
    )
    

    【讨论】:

      【解决方案4】:

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

      它会自动去除前导空格和换行符,所以有点方便。

      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
      

      【讨论】:

        【解决方案5】:

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

        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;'
        

        【讨论】:

          【解决方案6】:

          试试这个,

          #!/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} .$_ . ',';
              }
          }
          

          打印 Dumper $hash;

          【讨论】:

            猜你喜欢
            • 2011-11-29
            • 2019-05-10
            • 2020-01-29
            • 1970-01-01
            • 2011-11-22
            • 1970-01-01
            • 2014-07-13
            • 2019-10-22
            • 1970-01-01
            相关资源
            最近更新 更多