佩尔;如何按值过滤散列(指定条件)
Perl; how to filter an hash by value (specifying a condition)
我不是 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";
}
这次对我来说似乎很复杂,如果你们中的任何人能帮助我,我会很高兴。
使用 Data::Dumper
检查你的散列,你会发现你没有你认为的数据结构:
use strict;
use warnings;
use Data::Dumper;
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
的最后一个唯一条目。哈希键 必须 是唯一的
正如另一位发帖人所提到的 - 你的问题不是你的哈希合并,而是哈希不能有重复的键:
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;
这可以正常工作 - 请注意不同的哈希键。不过我会注意到 - 你正在迭代你的密钥,grepping它们,然后删除它们。可能更好:
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
来测试这两种情况。
我不是 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";
}
这次对我来说似乎很复杂,如果你们中的任何人能帮助我,我会很高兴。
使用 Data::Dumper
检查你的散列,你会发现你没有你认为的数据结构:
use strict;
use warnings;
use Data::Dumper;
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
的最后一个唯一条目。哈希键 必须 是唯一的
正如另一位发帖人所提到的 - 你的问题不是你的哈希合并,而是哈希不能有重复的键:
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;
这可以正常工作 - 请注意不同的哈希键。不过我会注意到 - 你正在迭代你的密钥,grepping它们,然后删除它们。可能更好:
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
来测试这两种情况。