Perl的;如何按值过滤哈希值(指定条件)

时间:2015-06-25 10:48:36

标签: perl hash filter subset

我在perl语言方面不是很专业但是我遇到了一个我无法解决的问题,即使经过长时间的网络研究。 简而言之,我有一个像这样的散列哈希:

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr1 => { start => 18, end => 21, },
    chr1 => { start => 30, end => 80, }
);

我只想找到一种方法来过滤它(我的意思是,在输出中获得新的散列哈希)以获取特定值。特别是,给定一个区间,比方说40-60,我想要一个新的哈希散列,只有元素重叠这个区间。

换句话说,我想得到输出:

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr1 => { start => 30, end => 80, }
);

作为第一次尝试,我想尝试这样的事情:

使用"end" < 40识别并删除所有元素,然后: 使用"start" > 60识别并删除所有元素。

所以我试过了:

grep { $HoH{$_}{"end"} < 40 } keys(%HoH); 
delete $HoH{$_} for grep { $HoH{$_}{"end"} < 40} keys(%HoH);

但是在两个过滤器中的第一个之后,我在输出中找到了最后一个元素,我真的不明白错误在哪里:

hash size is 1
chr1: start=30 end=80 

打印出以下内容:

my $len = keys %HoH;
print "hash size is $len\n";

foreach my $chr ( keys %HoH ) {
   print "$chr: ";
   for my $position ( keys %{ $HoH{$chr} } ) {
      print "$position=$HoH{$chr}{$position} ";
   }
   print "\n";
}

这次对我来说似乎相当复杂,如果有人能给我一些帮助,我会很高兴。

2 个答案:

答案 0 :(得分:3)

使用Data::Dumper检查您的哈希值,您会发现自己没有自己认为的数据结构:

use strict;
use warnings;

my %HoH = (
          chr1 => {
                   start => 30,
                   end => 55,
          },
          chr1 => {
                   start => 18,
                   end => 21,
                   },
          chr1 => {
                   start => 30,
                   end => 80,
                   },
            );

print Dumper \%HoH;     
$VAR1 = {
          'chr1' => {
                      'start' => 30,
                      'end' => 80
                    }
        };

正在发生的事情是它正在为chr1获取最后一个唯一条目。哈希键必须是唯一的

答案 1 :(得分:3)

正如另一张海报所提到的 - 你的问题不是你的哈希合并,它的哈希不能有重复的键:

use strict;
use warnings;
use Data::Dumper;

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr2 => { start => 18, end => 21, },
    chr3 => { start => 30, end => 80, }
);


grep { $HoH{$_}{"end"} < 40 } keys(%HoH); 
delete $HoH{$_} for grep { $HoH{$_}{"end"} < 40} keys(%HoH);

print Dumper \%HoH;

这可以正常工作 - 注意不同的哈希键。我会注意到 - 你正在重复你的密钥,轻击它们,然后删除它们。可能更好:

foreach my $element ( keys %HoH ) {
    delete $HoH{$element}
        unless ( $HoH{$element}{start} < 40
              or $HoH{$element}{end}   > 60 );
}

print Dumper \%HoH;

你可以通过一系列哈希来做你想做的事情:

use strict;
use warnings;
use Data::Dumper;

my @AoH = (
    { start => 30, end => 55, },
    { start => 18, end => 21, },
    { start => 30, end => 80, }
);

print Dumper \@AoH;

my @filtered = grep { $_->{start} > 40 or $_->{end} < 60 } @AoH;
print Dumper \@filtered;

注意 - 在原始示例中,您的grep / delete行正在执行相同操作,您可以执行复合grep来测试这两个条件。