我有哈希哈希
my %change;
while ( <DATA> ) {
chomp;
my ($gene, $condition, $change) = split;
$change{$gene}{$condition} = $change;
}
print Dumper \%change;
__DATA__
gene1 condition1 10
gene2 condition1 0.5
gene3 condition1 1.5
gene1 condition2 2
gene2 condition2 13.5
gene3 condition2 0.25
我想按价值对其进行排序:
gene2 condition2 13.5
gene1 condition1 10
gene1 condition2 2
gene3 condition1 1.5
gene2 condition1 0.5
gene3 condition2 0.25
我正在使用:
for my $g (keys %change){
for my $con (keys $change{$g}){
for my $ch (sort { $change{$g}{$a} <=> $change{$g}{$b} } keys $change{$g}{$con} ) {
print "$g\t$con\t$ch\n";
}
}
}
但这不起作用,并产生错误
引用键上的参数类型必须是unsitled hashref或arrayref at untitled.pl第23行第6行。
第23行
for my $ch (sort { $change{$g}{$a} <=> $change{$g}{$b} } keys $change{$g}{$con}){
有人能指出我正确的方向吗?
答案 0 :(得分:5)
我认为你不太可能需要像这样的哈希结构中的数据。当然,出于此任务的目的,您最好使用数组数组
use strict;
use warnings;
my @change;
while ( <DATA> ) {
push @change, [ split ];
}
print "@$_\n" for sort { $b->[2] <=> $a->[2] } @change;
__DATA__
gene1 condition1 10
gene2 condition1 0.5
gene3 condition1 1.5
gene1 condition2 2
gene2 condition2 13.5
gene3 condition2 0.25
gene2 condition2 13.5
gene1 condition1 10
gene1 condition2 2
gene3 condition1 1.5
gene2 condition1 0.5
gene3 condition2 0.25
如果您解释数据需要什么样的访问权限,那么我相信有更好的选择。例如,我建议%gene
和%condition
哈希将基因或条件ID映射到使用该基因的数组元素列表。然后,当您知道基因或条件时,您可以访问数据
答案 1 :(得分:4)
正如我在评论中提到的,最简单的解决方案是不首先将文本输入解析为散列,然后对散列进行排序,而是将数据收集到更合适的形式并在那里进行排序。
另外,请注意,在迭代值时无法进行排序。您需要编译一个列表,并同时对该列表进行排序,因为sort
本身就是一种迭代器。
我首先展示了我给出的输入方法的选择,然后是如何对哈希进行排序。
use strict;
use warnings;
my %change;
my @sort;
while(<DATA>) {
chomp;
my ($gene, $condition, $change) = split;
$change{$gene}{$condition} = $change;
push @sort, [ $change, $_ ];
}
@sort = sort { $a->[0] <=> $b->[0] } @sort;
say $_->[1] for @sort;
# Using the hash:
my @values;
for my $gene (keys %change) {
for my $con (keys %{ $change{$gene} }) {
my $num = $change{$gene}{$con};
push @values, [ $num, "$gene\t$con\t$num" ];
}
}
@values = sort { $a->[0] <=> $b->[0] } @values;
say $_->[1] for @values;
__DATA__
gene1 condition1 10
gene2 condition1 0.5
gene3 condition1 1.5
gene1 condition2 2
gene2 condition2 13.5
gene3 condition2 0.25
正如您所看到的,我正在使用一种缓存来更轻松地访问该值。例如,push @sort, [ $change, $_ ]
存储带有数值的数组ref,以及来自输入的原始字符串。然后可以在排序时使用$a->[0]
访问这些值,并在打印时使用$_->[1]
。
我发现这种方法简单而强大。虽然如果输入文件非常大,但由于数据重复,可能会导致一些内存问题。但是在现代系统中,任何小于千兆字节的东西都应该没问题。
答案 2 :(得分:3)
您可以展平哈希结构,然后按值(数组数组中的最后一个元素)按数字排序
my $VAR1 = {
'gene1' => {
'condition1' => '10',
'condition2' => '2'
},
'gene2' => {
'condition1' => '0.5',
'condition2' => '13.5'
},
'gene3' => {
'condition1' => '1.5',
'condition2' => '0.25'
}
};
my @sorted = sort {
$b->[2] <=> $a->[2]
}
map {
my $k = $_;
my $h = $VAR1->{$k};
map [ $k, $_, $h->{$_} ], keys %$h;
}
keys %$VAR1;
print "@$_\n" for @sorted;
输出
gene2 condition2 13.5
gene1 condition1 10
gene1 condition2 2
gene3 condition1 1.5
gene2 condition1 0.5
gene3 condition2 0.25
使用foreach
代替map
,
my @arr;
for my $k (keys %$VAR1) {
my $h = $VAR1->{$k};
for (keys %$h) {
push @arr, [ $k, $_, $h->{$_} ];
}
}
my @sorted = sort { $b->[2] <=> $a->[2] } @arr;
答案 3 :(得分:3)
你只有两个深度,所以
%change
是哈希。$change{$g}
是对哈希%{ $change{$g} }
是哈希。$change{$g}{$con}
是一个数字。%{ $change{$g}{$con} }
是错误。修复是......好吧,没有修复。您采用的方法无法用于解决您的问题。
您无法对哈希进行排序。您可以对哈希的键进行排序,但这不是您想要的。您将要对密钥对进行排序。首先,您必须创建这些密钥对。
map {
my $outer_key = $_;
map {
my $inner_key = $_;
[ $outer_key, $inner_key ]
} keys %{ $change{$_} }
} keys(%change)
这会创建
[
[ 'gene1', 'condition1' ],
[ 'gene1', 'condition2' ],
[ 'gene2', 'condition1' ],
[ 'gene2', 'condition2' ],
[ 'gene3', 'condition1' ],
[ 'gene3', 'condition2' ],
]
当我们对它们进行排序时
sort { $change{ $a->[0] }{ $a->[1] } <=> $change{ $b->[0] }{ $b->[1] }
所有在一起:
for (
sort { $change{ $a->[0] }{ $a->[1] } <=> $change{ $b->[0] }{ $b->[1] }
map {
my $gene = $_;
map {
my $con = $_;
[ $gene, $con ]
} keys %{ $change{$_} }
} keys(%change)
) {
my ($gene, $con) = @$_;
print("$g\t$con\t$change{$gene}{$con}\n");
}
但是,如果我们创建了以下扁平化结构呢?
[
[ 'gene1', 'condition1', 10 ],
[ 'gene1', 'condition2', 2 ],
[ 'gene2', 'condition1', 0.5 ],
[ 'gene2', 'condition2', 13.5 ],
[ 'gene3', 'condition1', 1.5 ],
[ 'gene3', 'condition2', 0.25 ],
]
这可以让我们简化一些。
for (
sort { $a->[2] <=> $b->[2] }
map {
my $gene = $_;
map {
my $con = $_;
[ $gene, $con, $change{$gene}{$con} ]
} keys %{ $change{$_} }
} keys(%change)
) {
my ($gene, $con, $ch) = @$_;
print("$g\t$con\t$ch\n");
}