如何在Perl中对并行数组进行排序?

问题描述:

我有几个相同长度的数组。我想排序第一个数组,并相应地使所有其他数组“排序”。例如,如果第一个数组是(7,2,9),第二个数组是("seven","two","nine"),第三个数组是("VII","II","IX")(按照第一个数组值递增),我们将有(2,7,9)("two","seven","nine")("II","VII","IX")如何在Perl中对并行数组进行排序?

我该怎么做?

+0

我会使用一个复杂的数据结构,而不是数组(阵列,散列数组或哈希数组/哈希S)。 – MvanGeest 2010-08-01 13:52:00

重新组织数据,以一个单一的阵列,用于排序:

my @a = ([7, "seven", "VII"], [2, "two", "II"], ..); 
@a = sort { $a->[0] <=> $b->[0] } @a; 

然后重新创建原始阵列:

my(@a1, @a2, @a3); 

for (@a) { 
    push @a1, shift @$_; 
    push @a2, shift @$_; 
    push @a3, shift @$_; 
} 

如你发现,保持平行阵列可以是一个麻烦和错误俯卧。另一种方法是将相关信息保存在一起。

use strict; 
use warnings; 

# One array-of-hashes instead of three parallel arrays. 
my @numbers = (
    { arabic => 7, text => 'seven', roman => 'VII' }, 
    { arabic => 2, text => 'two', roman => 'II' }, 
    { arabic => 9, text => 'nine', roman => 'IX' }, 
); 

@numbers = sort { $a->{arabic} <=> $b->{arabic} } @numbers; 

虽然我同意尤金y和MvanGeest,通常最好的答案是切换到另一种数据结构,有时您可能并行阵列(或至少,可能无法避免它们)实际上一种并行排序并行数组的方法。它是这样的:

my @nums = (7, 2, 9); 
my @names = qw(seven two nine); 
my @roman = qw(VII II IX); 

my @sorted_indices = sort { $nums[$a] <=> $nums[$b] } 0..$#nums; 
@$_ = @{$_}[@sorted_indices] for \(@nums, @names, @roman); 

也就是说,产生指数对应于所有阵列的列表,然后根据,将放在“主”数组中的顺序进行排序它们。一旦我们有了索引的排序列表,重新排列所有数组以匹配。

最后一行可以写手写出来作为

@nums = @nums[@sorted_indices]; 
@names = @names[@sorted_indices]; 
@roman = @roman[@sorted_indices]; 

但我想,以减少所需的复制粘贴的量,甚至在某些微毛语法的成本。更多你知道...

+1

+1光滑。根据以下几行提出一个通用函数的概念:'sub sort_parallel_arrays {my($ comparator,@arrays)= @_; ''。 – FMc 2010-08-01 15:59:15

+0

+1确实非常酷! – 2010-08-01 17:18:35

我知道你已经接受了一个答案,并且还有其他很好的 答案在这里,但我会建议一些不同的:不要复制你的 数据。你只需要追踪一次阿拉伯数字 - >罗马映射 - 为什么 存储基本上重复的数字数组,并对每一个数组进行排序? 只是排序主列表,并根据需要查找的引用数组中的其他值:

my @roman = qw(0 I II III IV V VI VII VIII IX X); 
my @text = qw(zero one two three four five six seven eight nine ten); 

my @values = (7, 2, 9); 
my @sorted_values = sort @values; 
my @sorted_roman = map { $roman[$_] } @sorted_values; 
my @sorted_text = map { $text[$_] } @sorted_values; 

use Data::Dumper; 
print Dumper(\@sorted_values, \@sorted_roman, \@sorted_text); 

打印:

$VAR1 = [ 
      2, 
      7, 
      9 
     ]; 
$VAR2 = [ 
      'II', 
      'VII', 
      'IX' 
     ]; 
$VAR3 = [ 
      'two', 
      'seven', 
      'nine' 
     ]; 

在实际环境中,我会建议使用库来执行 罗马并为您的文字转换:

use Roman; 
my @sorted_roman = map { roman($_) } @sorted_values; 

use Lingua::EN::Numbers 'num2en'; 
my @sorted_text = map { num2en($_) } @sorted_values; 
+0

+1:这与hobbs的建议非常相似,但语法更清晰,不是吗? – 2010-08-02 06:27:09

+2

@David:不是真的;霍布斯的方法仍然存储每种格式的数字列表,对数字列表进行排序,然后使用这些列表的索引作为指导来排序其他格式。我放弃了完全存储其他值的列表,并且之后只需从主转换表(或外部转换模块)查找它们。如果你要对需要同时排序的东西进行排序,但你不能轻易地从一个转换到另一个(即你需要存储两个版本),hobbs的方法就是要走的路,否则,使用查找表。 – Ether 2010-08-02 15:23:28