如何在Perl中重新排序列表元素

时间:2019-04-03 00:07:01

标签: perl

我在Perl中有一个列表。

@alist=("a_vld","a_sf","a_ef","a_val");
print join(',', @alist), "\n";

输出:

a_vld,a_sf,a_ef,a_val

如何重新排列列表中的元素,使其输出如下预期的输出:

a_sf,a_ef,a_vld,a_val

注意:a_将继续使用不同的字符串进行更改,但是我想保留sf,ef,vld,val的顺序

3 个答案:

答案 0 :(得分:6)

按给定集合排序(排序)的一种方法是将数字顺序与其元素相关联。

然后,我们需要在列表中的字符串中找到这些键进行排序。通过Schwartzian转换在实际排序之前完成一次。

use List::Util qw(first);

my @alist = ("a_vld", "a_sf", "a_ef", "a_val");

my @keys = qw(sf ef vld val);                       # keys to sort by
my %order_by = map { $keys[$_] => $_ } 0..$#keys;

my @sorted = 
    map { $_->[0] }
    sort { $order_by{$a->[1]} <=> $order_by{$b->[1]} }
    map {
        my $elem = $_;
        [ $elem, first { $elem =~ /$_/ } keys %order_by ]
    }
    @alist;

say "@sorted";

这将打印以下行:a_sf a_ef a_vld a_val

通过正则表达式在字符串中查找键,从而使列表中的元素与排序键相关联。考虑到这一点,上述内容可以合理地普遍使用,并带有所需的键列表。

答案 1 :(得分:5)

对于简短列表,请使用可按顺序标识序列的排序功能

@sorted = sort {
    ($b =~ /sf$/) <=> ($a =~ /sf$/)
        || ($b =~ /ef$/) <=> ($a =~ /ef$/)
        || ($b =~ /vld$/) <=> ($a =~ /vld$/)
        || ($b =~ /val$/) <=> ($a =~ /val$/)
} @alist;

答案 2 :(得分:3)

如果在代码之前始终有_,并且代码始终在结尾处

use Sort::Key qw( ikeysort );

my @order = qw( sf ef vld val );
my %order = map { $order[$_] => $_ } 0..$#order;

my @sorted = ikeysort { /_([^_\W]+)\z/ ? $order{$1} : 0 } @unsorted;

以上是以下内容的更快,更干净的版本:

my @order = qw( sf ef vld val );
my %order = map { $order[$_] => $_ } 0 .. $#order;

my @sorted =
   sort {
      my $key_a = /_([^_\W]+)\z/ ? $order{$1} : 0;
      my $key_b = /_([^_\W]+)\z/ ? $order{$1} : 0;
      $key_a <=> $key_b || $a cmp $b
   }
      @unsorted;

否则

use Sort::Key qw( ikeysort );

my @order = qw( sf ef vld val );
my %order = map { $order[$_] => $_ } 0..$#order;
my $alt = join '|', map quotemeta, @order;
my $re = qr/($alt)/;

my @sorted = ikeysort { /$re/ ? $order{$1} : 0 } @unsorted;

以上是以下内容的更快,更干净的版本:

my @order = qw( sf ef vld val );
my %order = map { $order[$_] => $_ } 0..$#order;
my $alt = join '|', map quotemeta, @order;
my $re = qr/($alt)/;

my @sorted =
   sort {
      my $key_a = /$re/ ? $order{$1} : 0;
      my $key_b = /$re/ ? $order{$1} : 0;
      $key_a <=> $key_b || $a cmp $b
   }
      @unsorted;