2016-11-10 4 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 - Вы должны были бы сделать некоторую работу для нахождения этих чисел в ваши строки, но принятый ответ - это то, что вам нужно конструктивно. Возможно, вы захотите объединить это с преобразованием Шварца. – 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 :: Naturally делает действительно хорошую работу с таким набором данных. См. Вывод второй части моего ответа. –

+0

@ChankeyPathak. Но я понял вопрос, потому что он не должен сортировать слова, которые у вас есть. Я думаю, это было немного неоднозначно в вопросе. Что произойдет с 'no_first_number_1' в вашем решении? – simbabque

Смежные вопросы