我有一个哈希,其密钥如下:
m2-10.10845.857-10.3145.857
m2-10.3145.857-10.42545.857
m2-10.42545.857-10.62845.857
m2-10.62845.857-10.83645.857
m2-11.60745.857-12.11745.857
m2-7.80945.857-8.01645.857
m2-8.01645.857-8.13145.857
m2-8.13145.857-8.24645.857
m2-8.24645.857-8.44345.857
m2-8.44345.857-9.7945.857
m2-9.7945.857-9.90545.857
m2-9.90545.857-10.10845.857
我想以一种他们看起来如下的方式对它们进行排序:
m2-11.60745.857-12.11745.857
m2-10.62845.857-10.83645.857
m2-10.42545.857-10.62845.857
m2-10.3145.857-10.42545.857
m2-10.10845.857-10.3145.857
m2-9.90545.857-10.10845.857
m2-9.7945.857-9.90545.857
m2-8.44345.857-9.7945.857
m2-8.24645.857-8.44345.857
m2-8.13145.857-8.24645.857
m2-8.01645.857-8.13145.857
m2-7.80945.857-8.01645.857
我试过
foreach my $key(sort {$h{$a} cmp $h{$b} } keys %h){
printf FHOUT "$h{$key}\n";
}
但它没有用。我该怎么做?
更新 刚刚想出了一个解决方案:
my @keys = sort{substr($h{$a},3,8) <=> substr($h{$b},3,8) } keys %h;
print "$_\n" for @keys;
但是,怎样才能使它更通用?
答案 0 :(得分:1)
问题中显示的两个示例都是通过比较值而不是键来排序的。我将使用该语句按键排序。为简单起见,我们可以考虑使用给定元素对数组进行排序的问题。
您似乎希望按第一个数字排序,然后按第二个数字排序,然后按第三个排序。第二组数字(在第二组-
之后)似乎并不重要。此外,因为它总是m2
我会忽视它。
按数字排序我们使用数字排序(<=>
),而不是词典(cmp
)。
然后将第一组数字分解为其组件并排序
foreach my $key ( sort { by_component($a, $b) } (keys %h) ) {
print "$key\n";
}
sub by_component {
my ($aa, $bb) = @_;
my @num_aa = split /\./, (split /-/, $aa)[1]; #/
my @num_bb = split /\./, (split /-/, $bb)[1];
return
$num_bb[0] <=> $num_aa[0] ||
$num_bb[1] <=> $num_aa[1] ||
$num_bb[2] <=> $num_aa[2];
}
<=>
运算符如果左边的操作数大于右边,则返回1
,如果它们相等,则返回0
;如果右边的值更大,则返回-1
。 1
或-1
都是&#34; true&#34;所以整个表达式都是真的,返回值。 0
为false,然后评估||
后的下一个条件 - 如果第一对相等,我们按下一个数字排序。
这将打印所需的键顺序。
请参阅sort和<=>
and cmp
operators以及logical operators了解上述行为。
答案 1 :(得分:0)
$a
接受任何返回$b
和#!/usr/bin/env perl
use strict;
use warnings;
sub custom_sort {
my @a_keys = split /[-\.]/, $a;
my @b_keys = split /[-\.]/, $b;
#check each key until 'array' is empty.
while ( @a_keys and @b_keys ) {
#if both are numeric, compare numerically.
if ( $a_keys[0] =~ /^\d+$/
and $b_keys[0] =~ /^\d+$/ )
{
my $comparison = shift @b_keys <=> shift @a_keys;
#returns a result if it's anything other than '0' e.g. they're the same.
return $comparison if $comparison;
}
else {
#compare stringwise.
my $comparison = shift @b_keys cmp shift @a_keys;
return $comparison if $comparison;
}
}
#fell through all the comparisons, so identical.
return 0;
}
chomp ( my @values = <DATA> );
print join ("\n", sort {custom_sort} @values ), "\n";
__DATA__
m2-10.10845.857-10.3145.857
m2-10.3145.857-10.42545.857
m2-10.42545.857-10.62845.857
m2-10.62845.857-10.83645.857
m2-11.60745.857-12.11745.857
m2-7.80945.857-8.01645.857
m2-8.01645.857-8.13145.857
m2-8.13145.857-8.24645.857
m2-8.24645.857-8.44345.857
m2-8.44345.857-9.7945.857
m2-9.7945.857-9.90545.857
m2-9.90545.857-10.10845.857
的位置比较符的函数。
我建议您尝试做的是将字符串分解为字段,并按字段比较字段&#39;排序。我已选择“处理”#39;我的例子中的字符串比较,但因为他们所有&#39; m2&#39;前缀,对结果没有任何影响。注意 - 一切都在下降&#39;在我的例子中,所以&#39; m1&#39;将比&#39; m3&#39;更低,与&#39; 7&#39;相同。比#11;&#39;低于订单。
m2-11.60745.857-12.11745.857
m2-10.62845.857-10.83645.857
m2-10.42545.857-10.62845.857
m2-10.10845.857-10.3145.857
m2-10.3145.857-10.42545.857
m2-9.90545.857-10.10845.857
m2-9.7945.857-9.90545.857
m2-8.44345.857-9.7945.857
m2-8.24645.857-8.44345.857
m2-8.13145.857-8.24645.857
m2-8.01645.857-8.13145.857
m2-7.80945.857-8.01645.857
这是通过价值,一个字段&#39;一次,并比较它们 - 如果比较&#39;那么转到下一个。为零(例如它们相等)。
作为输出:
{{1}}