如何使用“=”和“。”对哈希字母数字键进行排序。

时间:2017-06-02 09:29:14

标签: perl sorting

我有一个哈希,其密钥如下:

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;

但是,怎样才能使它更通用?

2 个答案:

答案 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;如果右边的值更大,则返回-11-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}}