perl哈希中的自定义字母排序
custom alphabetic sort in perl hash
我有一个散列,其结构如下:
my %my_hash=(
'gee1' => {
'gene' => '20',
'mRNA' => '9',
'CDS' => '10',
'exon' => '10',
'product' => '10',
},
'gee2' => {
'gene' => 'aa',
'mRNA' => '9',
'CDS' => '1aa',
'exon' => '1aa',
'product' => 'ab',
},
'gee4' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
},
'gee11' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
});
当我尝试按上述顺序打印散列时,使用以下代码:
for my $id ( sort { my ($anum) = ($a =~ /\w(\d+)$/); my ($bnum) = ($b =~ /\w(\d+)$/); $anum <=> $bnum} keys %my_hash)
{
print "$id\n";
for my $id1 (keys %{$my_hash{$id}})
{
print "\t$id1\n";
}
}
输出是这样的:
gee1
product
exon
gene
mRNA
CDS
gee2
product
exon
CDS
mRNA
gene
gee4
product
locus
gene
rRNA
gee11
rRNA
gene
product
locus
你可以看到
product
exon
gene
mRNA
CDS
以上部分未按顺序排列
他们有什么方法可以对上面的部分进行排序吗?
订单如下:
基因、mRNA、rRNA、CDS、外显子、产物、基因座
您只需要将子键的显示顺序定义为:
sub by_int_suffix{
my ($anum) = ($a =~ /\w(\d+)$/);
my ($bnum) = ($b =~ /\w(\d+)$/);
$anum <=> $bnum;
}
my @sub_key_order = qw(gene mRNA rRNA CDS exon product locus);
my @key_order = sort by_int_suffix keys %my_hash;
for my $id ( @key_order ){
print "$id\n";
for my $id1 (@sub_key_order){
next unless exists $my_hash{$id}->{$id1};
print "\t$id1\n";
}
}
只需创建一个哈希,您可以根据该哈希对键进行排序:
my %keys_sort;
my $c = 0;
$keys_sort{$_} = $c++ for qw( gene mRNA rRNA CDS exon product locus );
并用它对它们进行排序:
for my $id1 (sort { $keys_sort{$a} <=> $keys_sort{$b} }
keys %{ $my_hash{$id} }
) {
或者,直接使用列表,但 grep
只有相关键:
for my $id1 (grep exists $my_hash{$id}{$_},
qw( gene mRNA rRNA CDS exon product locus )
) {
对于那种长度的排序例程,我强烈建议您停止尝试作为匿名子程序嵌入。
排序将引用子例程。这个子例程可以采用任何通用的 $a
和 $b
和 return -1、0 或 1。(例如 cmp
或 <=>
做)绝对基于任何你喜欢的标准。
这里需要特别注意的是 - 哈希值是明确无序的。事实上,它们通常是在幕后故意随机排序的。所以你需要 也 排序你的 'inner' 散列。
考虑到这一点,我会建议这样的事情:
use strict;
use warnings;
my %my_hash = (
'gee1' => {
'gene' => '20',
'mRNA' => '9',
'CDS' => '10',
'exon' => '10',
'product' => '10',
},
'gee2' => {
'gene' => 'aa',
'mRNA' => '9',
'CDS' => '1aa',
'exon' => '1aa',
'product' => 'ab',
},
'gee4' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
},
'gee11' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
}
);
sub sort_key_number {
my ($anum) = ( $a =~ /(\d+)$/ );
my ($bnum) = ( $b =~ /(\d+)$/ );
#print "$anum, $bnum\n";
return $anum <=> $bnum;
}
my @subkeys = qw ( gene mRNA rRNA CDS exon product locus );
foreach my $key ( sort {sort_key_number} keys %my_hash ) {
print "\n", $key, ":\n";
foreach my $subkey (@subkeys) {
print "\t", $subkey, " = ", $my_hash{$key}{$subkey} || '', "\n";
}
}
您已按 'key number' 对外部哈希进行排序。而你的内部散列,你每次都按特定顺序处理(由 @subkeys
定义)。
如果你想要一点技巧,最后一个 foreach
循环你可以用切片来做:
print join ( "\n\t", @{$my_hash{$key}}{@subkeys} );
但为了清楚起见,我决定不这样做。
只显示二级hash的keys有点不正常,不过答案是用一个单独的数组——这里我用了@required
— 定义您想要的键和顺序
其他人已经解释了一些非常相似的东西,所以在这里我使用 grep
来稍微改变一下。我没有打印每个子哈希的键,而是选择打印存在对应键
的 @required
的元素
出于同样的原因,我使用 map
创建了一对需要在外部 sort
操作中进行比较的数值
use strict;
use warnings;
use 5.010;
my %my_hash=(
gee1 => { CDS => 10, exon => 10, gene => 20, mRNA => 9, product => 10 },
gee11 => { gene => "aa", locus => "abc", product => "ab", rRNA => 9 },
gee2 => { CDS => "1aa", exon => "1aa", gene => "aa", mRNA => 9, product => "ab" },
gee4 => { gene => "aa", locus => "abc", product => "ab", rRNA => 9 },
);
my @sorted_keys = sort {
my ($aa, $bb) = map /(\d+)/, $a, $b;
$aa <=> $bb;
} keys %my_hash;
my @required = qw/ gene mRNA rRNA CDS exon product locus /;
for my $key ( @sorted_keys ) {
print "$key\n";
for ( grep exists $my_hash{$key}{$_}, @required ) {
print " $_\n";
}
}
输出
gee1
gene
mRNA
CDS
exon
product
gee2
gene
mRNA
CDS
exon
product
gee4
gene
rRNA
product
locus
gee11
gene
rRNA
product
locus
更新
那些丢失的哈希值困扰着我,我应该指出,您可以通过将最后一个 print
语句更改为
来非常简单地生成它们
print " $_ = $my_hash{$key}{$_}\n"
现在的输出是
gee1
gene = 20
mRNA = 9
CDS = 10
exon = 10
product = 10
gee2
gene = aa
mRNA = 9
CDS = 1aa
exon = 1aa
product = ab
gee4
gene = aa
rRNA = 9
product = ab
locus = abc
gee11
gene = aa
rRNA = 9
product = ab
locus = abc
你一次做的太多了。使用两个循环。外循环用于对 %my_hash
基因进行排序,内循环用于对基因项目进行排序:
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
my %my_hash=(
'gee1' => { 'gene' => '20', 'mRNA' => '9', 'CDS' => '10', 'exon' => '10', 'product' => '10', },
'gee2' => { 'gene' => 'aa', 'mRNA' => '9', 'CDS' => '1aa', 'exon' => '1aa', 'product' => 'ab', },
'gee4' => { 'gene' => 'aa', 'rRNA' => '9', 'product' => 'ab', 'locus' => 'abc' },
'gee11' => { 'gene' => 'aa', 'rRNA' => '9', 'product' => 'ab', 'locus' => 'abc' },
);
for my $gene ( sort {fc $a cmp fc $b} keys %my_hash ) {
say $gene;
my %types = %{$my_hash{$gene}};
for my $type ( sort {fc $a cmp fc $b} keys %types ) {
say " $type: " . $my_hash{$gene}->{$type};
}
}
虽然我本可以直接对该数据集进行排序,但我注意到存在大写和小写键。使用纯 sort
命令将在 当前排序规则区域设置 中排序,这可能会将大写字母排在小写字母之前。使用 fc
折叠大小写。
也就是说,我是这样做的:
sort { fc $a cmp fc $b } @array;
而不只是:
sort @array;
您也可以考虑使用 Schwartzian Transformation,这可能会更快。如果不出意外,您可以使用 Schwartzian 转换按排序顺序保存数据,以防您不想立即打印出来。
我有一个散列,其结构如下:
my %my_hash=(
'gee1' => {
'gene' => '20',
'mRNA' => '9',
'CDS' => '10',
'exon' => '10',
'product' => '10',
},
'gee2' => {
'gene' => 'aa',
'mRNA' => '9',
'CDS' => '1aa',
'exon' => '1aa',
'product' => 'ab',
},
'gee4' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
},
'gee11' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
});
当我尝试按上述顺序打印散列时,使用以下代码:
for my $id ( sort { my ($anum) = ($a =~ /\w(\d+)$/); my ($bnum) = ($b =~ /\w(\d+)$/); $anum <=> $bnum} keys %my_hash)
{
print "$id\n";
for my $id1 (keys %{$my_hash{$id}})
{
print "\t$id1\n";
}
}
输出是这样的:
gee1
product
exon
gene
mRNA
CDS
gee2
product
exon
CDS
mRNA
gene
gee4
product
locus
gene
rRNA
gee11
rRNA
gene
product
locus
你可以看到
product
exon
gene
mRNA
CDS
以上部分未按顺序排列
他们有什么方法可以对上面的部分进行排序吗?
订单如下: 基因、mRNA、rRNA、CDS、外显子、产物、基因座
您只需要将子键的显示顺序定义为:
sub by_int_suffix{
my ($anum) = ($a =~ /\w(\d+)$/);
my ($bnum) = ($b =~ /\w(\d+)$/);
$anum <=> $bnum;
}
my @sub_key_order = qw(gene mRNA rRNA CDS exon product locus);
my @key_order = sort by_int_suffix keys %my_hash;
for my $id ( @key_order ){
print "$id\n";
for my $id1 (@sub_key_order){
next unless exists $my_hash{$id}->{$id1};
print "\t$id1\n";
}
}
只需创建一个哈希,您可以根据该哈希对键进行排序:
my %keys_sort;
my $c = 0;
$keys_sort{$_} = $c++ for qw( gene mRNA rRNA CDS exon product locus );
并用它对它们进行排序:
for my $id1 (sort { $keys_sort{$a} <=> $keys_sort{$b} }
keys %{ $my_hash{$id} }
) {
或者,直接使用列表,但 grep
只有相关键:
for my $id1 (grep exists $my_hash{$id}{$_},
qw( gene mRNA rRNA CDS exon product locus )
) {
对于那种长度的排序例程,我强烈建议您停止尝试作为匿名子程序嵌入。
排序将引用子例程。这个子例程可以采用任何通用的 $a
和 $b
和 return -1、0 或 1。(例如 cmp
或 <=>
做)绝对基于任何你喜欢的标准。
这里需要特别注意的是 - 哈希值是明确无序的。事实上,它们通常是在幕后故意随机排序的。所以你需要 也 排序你的 'inner' 散列。
考虑到这一点,我会建议这样的事情:
use strict;
use warnings;
my %my_hash = (
'gee1' => {
'gene' => '20',
'mRNA' => '9',
'CDS' => '10',
'exon' => '10',
'product' => '10',
},
'gee2' => {
'gene' => 'aa',
'mRNA' => '9',
'CDS' => '1aa',
'exon' => '1aa',
'product' => 'ab',
},
'gee4' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
},
'gee11' => {
'gene' => 'aa',
'rRNA' => '9',
'product' => 'ab',
'locus' => 'abc'
}
);
sub sort_key_number {
my ($anum) = ( $a =~ /(\d+)$/ );
my ($bnum) = ( $b =~ /(\d+)$/ );
#print "$anum, $bnum\n";
return $anum <=> $bnum;
}
my @subkeys = qw ( gene mRNA rRNA CDS exon product locus );
foreach my $key ( sort {sort_key_number} keys %my_hash ) {
print "\n", $key, ":\n";
foreach my $subkey (@subkeys) {
print "\t", $subkey, " = ", $my_hash{$key}{$subkey} || '', "\n";
}
}
您已按 'key number' 对外部哈希进行排序。而你的内部散列,你每次都按特定顺序处理(由 @subkeys
定义)。
如果你想要一点技巧,最后一个 foreach
循环你可以用切片来做:
print join ( "\n\t", @{$my_hash{$key}}{@subkeys} );
但为了清楚起见,我决定不这样做。
只显示二级hash的keys有点不正常,不过答案是用一个单独的数组——这里我用了@required
— 定义您想要的键和顺序
其他人已经解释了一些非常相似的东西,所以在这里我使用 grep
来稍微改变一下。我没有打印每个子哈希的键,而是选择打印存在对应键
@required
的元素
出于同样的原因,我使用 map
创建了一对需要在外部 sort
操作中进行比较的数值
use strict;
use warnings;
use 5.010;
my %my_hash=(
gee1 => { CDS => 10, exon => 10, gene => 20, mRNA => 9, product => 10 },
gee11 => { gene => "aa", locus => "abc", product => "ab", rRNA => 9 },
gee2 => { CDS => "1aa", exon => "1aa", gene => "aa", mRNA => 9, product => "ab" },
gee4 => { gene => "aa", locus => "abc", product => "ab", rRNA => 9 },
);
my @sorted_keys = sort {
my ($aa, $bb) = map /(\d+)/, $a, $b;
$aa <=> $bb;
} keys %my_hash;
my @required = qw/ gene mRNA rRNA CDS exon product locus /;
for my $key ( @sorted_keys ) {
print "$key\n";
for ( grep exists $my_hash{$key}{$_}, @required ) {
print " $_\n";
}
}
输出
gee1
gene
mRNA
CDS
exon
product
gee2
gene
mRNA
CDS
exon
product
gee4
gene
rRNA
product
locus
gee11
gene
rRNA
product
locus
更新
那些丢失的哈希值困扰着我,我应该指出,您可以通过将最后一个 print
语句更改为
print " $_ = $my_hash{$key}{$_}\n"
现在的输出是
gee1
gene = 20
mRNA = 9
CDS = 10
exon = 10
product = 10
gee2
gene = aa
mRNA = 9
CDS = 1aa
exon = 1aa
product = ab
gee4
gene = aa
rRNA = 9
product = ab
locus = abc
gee11
gene = aa
rRNA = 9
product = ab
locus = abc
你一次做的太多了。使用两个循环。外循环用于对 %my_hash
基因进行排序,内循环用于对基因项目进行排序:
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
my %my_hash=(
'gee1' => { 'gene' => '20', 'mRNA' => '9', 'CDS' => '10', 'exon' => '10', 'product' => '10', },
'gee2' => { 'gene' => 'aa', 'mRNA' => '9', 'CDS' => '1aa', 'exon' => '1aa', 'product' => 'ab', },
'gee4' => { 'gene' => 'aa', 'rRNA' => '9', 'product' => 'ab', 'locus' => 'abc' },
'gee11' => { 'gene' => 'aa', 'rRNA' => '9', 'product' => 'ab', 'locus' => 'abc' },
);
for my $gene ( sort {fc $a cmp fc $b} keys %my_hash ) {
say $gene;
my %types = %{$my_hash{$gene}};
for my $type ( sort {fc $a cmp fc $b} keys %types ) {
say " $type: " . $my_hash{$gene}->{$type};
}
}
虽然我本可以直接对该数据集进行排序,但我注意到存在大写和小写键。使用纯 sort
命令将在 当前排序规则区域设置 中排序,这可能会将大写字母排在小写字母之前。使用 fc
折叠大小写。
也就是说,我是这样做的:
sort { fc $a cmp fc $b } @array;
而不只是:
sort @array;
您也可以考虑使用 Schwartzian Transformation,这可能会更快。如果不出意外,您可以使用 Schwartzian 转换按排序顺序保存数据,以防您不想立即打印出来。