2016-11-10 71 views
3

我有下面的格式的密鑰的哈希:排序哈希抓好兩個參數

scaffold_902_159 
scaffold_2_1980420 
scaffold_2_10 
scaffold_10_402 

我要打印出來的格式如下排序的哈希:

scaffold_2_10 
scaffold_2_1980420 
scaffold_10_402 
scaffold_902_159 

所以第一我必須從數字上訂購第一個號碼,然後再參加最後一個號碼。我不希望正則表達式搜索「scaffold_」,因爲這可能會有所不同。我的意思是,我可以有像「blablabla_NUMBER_NUMBER,或blablablaNUMBER_NUMBER」等格式的哈希值。密鑰_NUMBER的最後一部分是唯一永久性的。

我有這個代碼,但只有數字順序排序出席的第一個數字:

my @keys = sort { 
      my ($aa) = $a =~ /(\d+)/; 
      my ($bb) = $b =~ /(\d+)/; 
      $aa <=> $bb; 
     } keys %hash; 
foreach my $key (@keys) { 
    print $key; 
} 

什麼建議嗎?

+1

相關,如果不重複:http://stackoverflow.com/q/8556331/1331451 - 你必須做一些工作,爲尋找這些數字你的字符串,但接受的答案是你需要的結構明智的。您可能希望將其與Schwartzian變換結合使用。 – simbabque

+0

是否有blablabla_NUMBER與修復發生或blablabla&NUMBER可能會變得像blablabla_blablabla_NUMBER? – AbhiNickz

+0

@AbhiNickz,想一想你的問題,也許有時可能會發生中間數字不是數字。這些出現應該出現在最後,並按第二個數字排序(總是存在) – cucurbit

回答

6

Sort::Naturally來救援!

#!/usr/bin/perl 
use strict; 
use warnings; 
use Sort::Naturally qw(nsort); 
my %hash = (
       scaffold_902_159 => 'v1', 
       scaffold_2_1980420 => 'v2', 
       scaffold_2_10 => 'v3', 
       scaffold_10_402 => 'v4', 
      ); 
print "$_\n" for nsort keys %hash; 

輸出:

scaffold_2_10 
scaffold_2_1980420 
scaffold_10_402 
scaffold_902_159 

根據您的查詢,嘗試了它不具有在中間的數字鍵部分。

#!/usr/bin/perl 
use strict; 
use warnings; 
use Sort::Naturally qw(nsort); 
my @keys = qw(
    should_come_last_9999_0 
    blablabla_10_403 
    scaffold_902_159 
    scaffold_2_1980420 
    scaffold_2_10 
    scaffold_10_402 
    blablabla902_1 
    blablabla901_3 
); 
print "$_\n" for nsort @keys; 

輸出:

blablabla_10_403 
blablabla901_3 
blablabla902_1 
scaffold_2_10 
scaffold_2_1980420 
scaffold_10_402 
scaffold_902_159 
should_come_last_9999_0 
+0

謝謝!我會嘗試一下並接受答案。你知道如果你沒有中間號碼的話會發生什麼? – cucurbit

+0

它會工作。正如模塊的描述所說:「Sort :: Naturally - 按詞彙排序,但是按數字排序數字部分」。 –

3

這個排序上兩列,並使用Schwartzian transform從您的字符串創建這些列。

use strict; 
use warnings; 
use feature 'say'; 

my @keys = qw(
    scaffold_902_159 
    scaffold_2_1980420 
    scaffold_2_10 
    scaffold_10_402 
); 

@keys = 
    map { $_->[0] }            # transform back 
    sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }   # sort 
    map {               # transform 
     m/(\d+)(?:\D+(\d+))/; 
     [ $_, (defined $2 ? ($1, $2) : (0xffffffff, $1)) ] 
    } @keys; 

say for @keys; 

輸出:

scaffold_2_10 
scaffold_2_1980420 
scaffold_10_402 
scaffold_902_159 

由初始轉化map返回的數據結構是這樣的:

[ 'scaffold_902_159', 902, 159 ] 

sort使用該由索引1(902)第一個排序上面用數字排序<=>。該操作員返回0如果兩個RHS和LHS是相等的,因此還是||與合適的表情繼續下去,那麼它排序上索引2(159)。

因爲你說的第一個數字是可選的,如果只有第二個數字是有這些元素應該最後來了,我們需要替換一個非常高的數字了點。沒有進入64位整數,0xffffffff是我們可以製造的最高數字。

第二個map從數組引用的索引0中提取完整的密鑰。

如果我們在輸入中添加其他內容,例如您建議的blablablaNUMBER_NUMBER,它仍然只對排序,並完全忽略字符串部分。

my @keys = qw(
    should_come_last_9999_0 
    blablabla_10_403 
    scaffold_902_159 
    scaffold_2_1980420 
    scaffold_2_10 
    scaffold_10_402 
    no_first_number_1 
); 

下面是輸出:

scaffold_2_10 
scaffold_2_1980420 
scaffold_10_402 
blablabla_10_403 
blablabla902_1 
scaffold_902_159 
should_come_last_9999_0 
no_first_number_1 
+1

評論http://stackoverflow.com/questions/40527747/sort-hash-attending-to-two-parameters/40528064#comment68296100_40527747使我的答案無效。 – simbabque

+0

我注意到Sort ::自然地對這樣一組數據做了很好的工作。看到我的答案的第二部分的輸出。 –

+0

@ChankeyPathak它呢。但我理解這個問題,因爲它不應該對你的文字進行排序。我認爲這個問題有點含糊。解決方案中的no_first_number_1會發生什麼情況? – simbabque