如何在perl中对包含两个数字的字符串数组进行排序?

时间:2015-07-03 21:02:40

标签: arrays string perl sorting numbers

我有以下字符串数组:

Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1

我想按第一个数字排序这些字符串,然后用第二个数字排序第二个数字,这样我就有了这样的列表:

Expt1_Expt2
Expt5_Expt1
Expt5_Expt12
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt11_Expt8
Expt12_Expt2

我只发现解决方案只按第一个数字或第二个数字排序。我尝试了一些使用正则表达式和排序函数的东西,但我没有找到解决方案。

3 个答案:

答案 0 :(得分:9)

按功能排序非常简单。该函数必须返回-1,0或1,具体取决于$a$b之前或之后。 (如评论中所述 - 它可以是任何正值或负值 - 关键点是元素是在彼此之前还是之后)。

$a$b是特殊的'专门用于perl和排序的变量。因此,他们不需要声明,并且在您的代码中用于其他内容的真的坏主意。但那么,谁还使用单字母变量?

所以你的价值观:

#!/usr/bin/env perl
use strict;
use warnings;

sub custom_sort {
   my ( $a1, $a2 ) = ( $a =~ m/(\d+)/g );   #extract the numeric elements
   my ( $b1, $b2 ) = ( $b =~ m/(\d+)/g );

   return ( $a1 <=> $b1     #return the result of this comparison
         || $a2 <=> $b2 );  #unless it's zero, then we return the result of this.
}


my @list = <DATA>;    
print sort custom_sort @list; 

__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1

你可以使这更简洁,但实质是:

  • 提取第一个和第二个值。
  • 然后使用||运算符 - 这样如果$a1 <=> $b1为零,它将计算表达式的第二部分。
  • <=>小于,等于,大于&#39;基于数字比较返回-1,0或1的运算符。对于字符串,您可以使用cmp执行相同的操作。

(如果您希望调试这种类型的工作方式,那么您可以打印这些,以便进行每次比较,如果您正在做一些复杂的事情,这非常方便)

答案 1 :(得分:2)

这与其他人发布的解决方案基本相同,但使用map

更简洁
use strict;
use warnings;

my @data = <DATA>;

print sort {
    my @ab = map [ /\d+/g ], $a, $b;
    $ab[0][0] <=> $ab[1][0] or $ab[0][1] <=> $ab[1][1];
} @data;

__DATA__
Expt5_Expt12
Expt5_Expt1
Expt12_Expt2
Expt11_Expt8
Expt1_Expt2
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1

输出

Expt1_Expt2
Expt5_Expt1
Expt5_Expt12
Expt10_Expt1
Expt10_Expt4
Expt11_Expt1
Expt11_Expt8
Expt12_Expt2

答案 2 :(得分:1)

使用Sort::Key::Multi;

use Sort::Key::Multi qw(i2_keysort); #i2 means two integer keys

my @sorted = i2_keysort { /(\d+)\D+(\d+)/ } @data;