排序涉及两个参数的散列

Sort hash attending to two parameters

我有一个具有以下格式的密钥的散列:

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;
}

有什么建议吗?

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

这对两列进行排序,并使用 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  ? ( ,  ) : ( 0xffffffff,  ) ) ]
    } @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)和数字排序 <=> 进行排序。该运算符 returns 0 如果 RHS 和 LHS 都相等,则 or || 继续正确的表达式,然后按索引 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