2

类似于这个问题:按 Perl 字符串的子集排序

我想先按值排序,然后按键的子集。

我的%hash

 cat_02 => 0
 cat_04 => 1
 cat_03 => 0
 cat_01 => 3

输出(可以是按此顺序排列的键数组):

cat_02 => 0
cat_03 => 0
cat_04 => 1
cat_01 => 3

奖励:关键的辅助比较将识别 1234_2_C01 并且小于 1234_34_C01 (cmp不会)。

4

4 回答 4

8

利用:

my %hash = (
  cat_02 => 0,
  cat_04 => 1,
  cat_03 => 0,
  cat_01 => 3
);

print "$_ => $hash{$_}\n"
  for sort { $hash{$a} <=> $hash{$b} or $a cmp $b } keys %hash;

sort 对值进行数字比较,如果它们相等,or则执行后面的部分,对键进行字符串比较。这给出了您要求的输出。

要对包含数字和非数字内容的字符串进行智能排序,请从The Alphanum Algorithm中获取 alphanum 比较函数并替换$a cmp $balphanum($a,$b).

于 2013-05-23T22:38:35.297 回答
4

当您有辅助排序首选项时,您只需在排序例程中添加另一个级别:

my %hash = (
    cat_02 => 0,
    cat_04 => 1,
    cat_03 => 0,
    cat_01 => 3
);

my @sorted = sort { $hash{$a} <=> $hash{$b} || $a cmp $b } keys %hash;
                  #  primary sort method    ^^ secondary sort method
for (@sorted) {
    print "$_\t=> $hash{$_}\n";
}

输出:

cat_02  => 0
cat_03  => 0
cat_04  => 1
cat_01  => 3
于 2013-05-23T22:40:56.730 回答
3

这可以使用 Sort::Key:: 模块轻松完成(快速!):

use Sort::Key::Natural qw( );
use Sort::Key::Maker intnatkeysort => qw( integer natural );

my @sorted_keys = intnatkeysort { $hash{$_}, $_ } keys(%hash);

或者您可以利用数据的属性并使用自然排序:

use Sort::Key::Natural qw( natkeysort );

my @sorted_keys = natkeysort { "$hash{$_}-$_" } keys(%hash);
于 2013-05-23T23:45:03.627 回答
1

It may be not worth it in this particular case, but Schwartzian transform technique can be used with multi-criteria sort too. Like this (codepad):

use warnings;
use strict;

my %myhash = (
  cat_2 => 0, cat_04 => 1,
  cat_03 => 0, dog_02 => 3, 
  cat_10 => 0, cat_01 => 3,
);

my @sorted = 
    map { [$_->[0], $myhash{$_->[0]}] } 
    sort { $a->[1] <=> $b->[1]  or  $a->[2] <=> $b->[2] } 
    map { m/([0-9]+)$/ && [$_, $myhash{$_}, $1] } 
    keys %myhash;

print $_->[0] . ' => ' . $_->[1] . "\n" for @sorted;

Obviously, the key to this technique is using more than one additional element in the cache.

Two things here: 1) @sorted actually becomes array of arrays (each element of this array is key-value pair); 2) sorting in this example is based on keys' digits suffix (with numeric, not string comparison), but it can be adjusted in any direction if needed.

For example, when keys match pattern XXX_DD_XXX (and it's DD that should be compared), change the second map clause with this:

    map { m/_([0-9]+)_/ && [$_, $myhash{$_}, $1] } 
于 2013-05-23T22:50:56.793 回答