2010-08-01 128 views
2

我有幾個相同長度的數組。我想排序第一個數組,並相應地使所有其他數組「排序」。例如,如果第一個數組是(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

回答

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

雖然我同意尤金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

6

我知道你已經接受了一個答案,並且還有其他很好的 答案在這裏,但我會建議一些不同的:不要複製你的 數據。你只需要追蹤一次阿拉伯數字 - >羅馬映射 - 爲什麼 存儲基本上重複的數字數組,並對每一個數組進行排序? 只是排序主列表,並根據需要查找的引用數組中的其他值:

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