【问题标题】:In Perl, how can I sort hash keys using a custom ordering?在 Perl 中,如何使用自定义排序对哈希键进行排序?
【发布时间】:2023-03-14 16:28:01
【问题描述】:

我正在尝试处理文件哈希,并且必须按特定顺序完成工作。大多数人会说列表可以这样排序:

for my $k (sort keys %my_hash)
{
    print "$k=>$my_hash{$k}, ";
}

但是,我需要非字母顺序,实际上键以单词开头,然后是 _,然后它们转到 GdigitsLM,P,R,T or D 中的任何一个(例如 word_G.txt,@ 987654328@,...,word_P.txt)。有没有办法按自定义顺序排序?

【问题讨论】:

  • 只需将您的排序条件放在排序关键字后面:while my $k (sort { $a < $b unless $a eq '_' } keys %my_hash) 等 ...

标签: perl sorting hash foreach


【解决方案1】:

有没有办法按自定义顺序排序?

是的。见sort

例如:

#!/usr/bin/env perl

use warnings; use strict;

my @order = qw(G 1 2 3 L M P R T D);

my %order_map = map { $order[$_] => $_ } 0 .. $#order;

my $pat = join '|', @order;

my @input = qw(word_P.txt word_2.txt word_G.txt);

my @sorted = sort {
    my ($x, $y) = map /^word_($pat)[.]txt\z/, $a, $b;
    $order_map{$x} <=> $order_map{$y}
} @input;

print "@sorted\n";

【讨论】:

  • 我看到了我认为是我想要的比较原型,但我能看到的唯一解决方案是一堆 if 语句。这是唯一的方法吗?
  • 您并没有很好地解释您的要求,所以我无法真正弄清楚什么可以解决特定问题。要以非默认方式排序,您需要编写一个比较函数。如果您解释该功能需要做什么,我们也许可以提供帮助。
  • 我认为这是我能解释的最好的,所以让我们换一种方式。而不是比较A,B,C,...,X,Y,Z 我想要G,1,2,3,L,M,P,R,T,D
  • 在 LHS 上,你有 26 个字母,在 RHS 上你有 10 个字符,所以我不知道它们应该如何相互映射。但是,如果您只想将以 G 开头的单词映射到以 1 开头的单词之前排序,您应该能够调整我发布的示例以满足您的需求。
  • 您的解决方案有效,但是当我将@ordermy @sorted = ... 更改为qw(word_P.txt word_2.txt word_G.txt) 时,有很多未初始化的值有没有办法处理这个问题?
【解决方案2】:
use 5.014;

sub rank {
    my ($word) = @_;
    $word =~ s{\A \w+ _}{}msx;
    return do {
        given ($word) {
            0 when /\A G/msx;
            1 when /\A [0-9]/msx;
            2 when /\A L/msx;
            3 when /\A [MPRTD]/msx;
            default { 1000 };
        }
    };
}

say for sort { rank($a) <=> rank($b) } qw(word_P.txt word_2.txt word_G.txt);

输出:

word_G.txt
word_2.txt
word_P.txt

编辑:在 Perl 5.14 之前,使用临时变量。

use 5.010;
⋮
return do {
    my $dummy;
    given ($word) {
        $dummy = 0 when /\A G/msx;
        $dummy = 1 when /\A [0-9]/msx;
        $dummy = 2 when /\A L/msx;
        $dummy = 3 when /\A [MPRTD]/msx;
        default { $dummy = 1000 };
    }
    $dummy;
};

【讨论】:

【解决方案3】:

我有一个特定的用例,我想先用某些值排序,最后用其他值排序,然后在中间按字母顺序排序。

这是我的解决方案:

my @sorted = sort {
    my @order = qw(Mike Dave - Tom Joe);
    my ($x,$y) = (undef,undef);
    for (my $i = 0; $i <= $#order; $i++) {
        my $token = $order[$i];
        $x = $i if ($token eq $a or (not defined $x and $token eq "-"));
        $y = $i if ($token eq $b or (not defined $y and $token eq "-"));
    }
    $x <=> $y or
    $a cmp $b
} @ARGV;

输出:

$ perl customsort.pl Tom Z Mike A Joe X Dave G
Mike Dave A G X Z Tom Joe

【讨论】:

    猜你喜欢
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 2019-03-17
    • 2012-01-21
    相关资源
    最近更新 更多