2017-06-02 28 views
1

我有具有鍵如下哈希:如何使用「=」和「。」來排序哈希字母數字鍵。

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

它是如何出來的?什麼不工作?請[編輯]你的問題,幷包括它的錯誤。 – simbabque

+0

它來如:'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' –

+0

您的問題與進一步的信息。 – Sobrique

回答

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都是「真」,因此整個表達式爲真,並且那個值返回0爲假,然後評估||後的下一個條件 - 如果第一對相等,我們按下一個數字排序。

這將打印所需的按鍵順序。

請參閱sort<=> and cmp operatorslogical operators瞭解上述行爲。

+0

謝謝!這工作完美!我只是根據我的要求調整了一下。 –

+0

您能否將退貨聲明翻譯成英文?準確地說,「||」的作用是什麼?這裏? –

+0

@tt_pre將做... – zdim

0

sort採用任何返回位置比較器的函數$a$b

我會建議你要做的是將你的字符串分解爲字段,並比較'字段字段'進行排序。在我的例子中,我選擇'處理'字符串比較,但是因爲它們都是'm2'前綴,所以對結果沒有任何影響。注意 - 在我的例子中,一切都是'降序',所以'm1'將低於'm3',與'7'相比,低於'11'。

#!/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 

這是通過在一個時間值,一個「場」,並對它們進行比較 - 移動到下一如果「比較」是零(例如它們是相等的)。

其中給出的輸出:

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