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

时间:2010-08-01 13:50:16

标签: perl arrays sorting

我有一些长度相同的数组。我想对第一个数组进行排序,并使所有其他数组相应地“排序”。例如,如果第一个数组为(7,2,9),则第二个数组为("seven","two","nine"),第三个数组为排序后的("VII","II","IX")(根据第一个数组值递增),我们将(2,7,9) ("two","seven","nine")("II","VII","IX")

我该怎么做?

4 个答案:

答案 0 :(得分:17)

虽然我同意eugene 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);

即,生成与所有数组对应的 indices 列表,然后根据将“主”数组按顺序排列的顺序对它们进行排序。一旦我们得到了索引的排序列表,就要重新排序所有数组以匹配。

最后一行可以写成

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

但是我试图减少必要的复制粘贴量,即使是以一些略带毛茸茸的语法为代价。你知道的更多......

答案 1 :(得分:6)

我知道你已经接受了答案,还有其他非常好的答案 答案在这里,但我会提出一些不同的东西:不要复制你的 数据。你只需要跟踪阿拉伯语 - &gt;罗马映射一次 - 为什么 存储什么是基本上重复的数字数组,并对每个数字进行排序? 只需对主列表进行排序,并根据需要在参考数组中查找其他值:

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;

答案 2 :(得分:5)

将数据重新组织到单个数组中进行排序:

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 @$_;
}  

答案 3 :(得分:4)

正如您所发现的,维护并行阵列可能很麻烦且容易出错。另一种方法是将相关信息保存在一起。

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;