Perl;如何按值筛选哈希(指定条件)

Perl;如何按值筛选哈希(指定条件),perl,hash,filter,subset,Perl,Hash,Filter,Subset,我对perl语言不是很精通,但我遇到了一个我无法解决的问题,即使在网上做了很长时间的研究。 简单地说,我有这样一个散列: my %HoH = ( chr1 => { start => 30, end => 55, }, chr1 => { start => 18, end => 21, }, chr1 => { start => 30, end => 80, } ); 我只是想找到一种方法来过滤它(我的意思是,在输出

我对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, }
);
作为第一次尝试,我想尝试以下内容:

my %HoH = (
    chr1 => { start => 30, end => 55, },
    chr1 => { start => 18, end => 21, },
    chr1 => { start => 30, end => 80, }
);
识别并删除带有
“end”<40的所有元素,以及:
用
“start”>60识别并删除所有元素

所以我试着:

grep { $HoH{$_}{"end"} < 40 } keys(%HoH); 
delete $HoH{$_} for grep { $HoH{$_}{"end"} < 40} keys(%HoH);
打印出以下内容:

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";
}

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

使用
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;     


发生的情况是,它正在为
chr1
获取最后一个唯一条目。散列键必须是唯一的

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

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;
使用严格;
使用警告;
使用数据::转储程序;
我的%HoH=(
chr1=>{start=>30,end=>55,},
chr2=>{start=>18,end=>21,},
chr3=>{start=>30,end=>80,}
);
grep{$HoH{${“end”}<40}键(%HoH);
删除grep{$HoH{$}{“end”}<40}密钥(%HoH)的$HoH{$};
打印转储程序\%HoH;
这是正确的-注意不同的散列键。不过我要指出的是,您正在迭代密钥,将它们变灰,然后删除它们。最好是:

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

print Dumper \%HoH;
foreach my$元素(键%HoH){
删除$HoH{$element}
除非($HoH{$element}{start}<40
或$HoH{$element}{end}>60);
}
打印转储程序\%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;
使用严格;
使用警告;
使用数据::转储程序;
我的@AoH=(
{开始=>30,结束=>55,},
{开始=>18,结束=>21,},
{开始=>30,结束=>80,}
);
打印转储程序\@AoH;
my@filtered=grep{$\>{start}>40或$\>{end}<60}@AoH;
打印转储程序\@已过滤;

注意-在原始示例中,您的
grep
/
delete
行执行相同的操作,您可以执行复合
grep
来测试这两种情况

你不可能有这样的数据结构,因为所有的键都是相同的,你是对的,我不记得散列的特性,它们不能在里面存储重复的键。最后一个解决方案似乎非常有用,而且操作很少!谢谢!!!!
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;