如何在Perl中对并行数组进行排序?
我有几个相同长度的数组。我想排序第一个数组,并相应地使所有其他数组“排序”。例如,如果第一个数组是(7,2,9)
,第二个数组是("seven","two","nine")
,第三个数组是("VII","II","IX")
(按照第一个数组值递增),我们将有(2,7,9)
("two","seven","nine")
和("II","VII","IX")
。如何在Perl中对并行数组进行排序?
我该怎么做?
重新组织数据,以一个单一的阵列,用于排序:
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光滑。根据以下几行提出一个通用函数的概念:'sub sort_parallel_arrays {my($ comparator,@arrays)= @_; ''。 – FMc 2010-08-01 15:59:15
+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;
+1:这与hobbs的建议非常相似,但语法更清晰,不是吗? – 2010-08-02 06:27:09
@David:不是真的;霍布斯的方法仍然存储每种格式的数字列表,对数字列表进行排序,然后使用这些列表的索引作为指导来排序其他格式。我放弃了完全存储其他值的列表,并且之后只需从主转换表(或外部转换模块)查找它们。如果你要对需要同时排序的东西进行排序,但你不能轻易地从一个转换到另一个(即你需要存储两个版本),hobbs的方法就是要走的路,否则,使用查找表。 – Ether 2010-08-02 15:23:28
我会使用一个复杂的数据结构,而不是数组(阵列,散列数组或哈希数组/哈希S)。 – MvanGeest 2010-08-01 13:52:00