Как вы сортируете параллельные массивы в Perl? - PullRequest
2 голосов
/ 01 августа 2010

У меня есть несколько массивов одинаковой длины. Я хочу отсортировать первый массив и сделать все остальные массивы "сортировать" соответственно. Например, если первый массив равен (7,2,9), второй - ("seven","two","nine"), а третий - ("VII","II","IX") после сортировки (по возрастанию в соответствии со значениями первого массива), у нас будет (2,7,9) ("two","seven","nine") и ("II","VII","IX").

Как я могу это сделать?

Ответы [ 4 ]

17 голосов
/ 01 августа 2010

Хотя я согласен с Евгением 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];

, но я попытался уменьшить количествокопирования-вставки необходимо, даже за счет некоторого слегка волосатого синтаксиса.Чем больше вы знаете ...

6 голосов
/ 01 августа 2010

Я знаю, что вы уже приняли ответ, и здесь есть другие действительно хорошие ответы, но я бы предложил что-то другое: не дублируйте ваши данные.Вам нужно только один раз отследить арабское -> римское сопоставление - зачем хранить то, что по сути является дублирующими массивами чисел, и сортировать все?Просто отсортируйте основной список и найдите другие значения в ссылочном массиве по мере необходимости:

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;
5 голосов
/ 01 августа 2010

Реорганизация данных в один массив для сортировки:

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 голосов
/ 01 августа 2010

Как вы обнаруживаете, поддержка параллельных массивов может быть хлопотной и подверженной ошибкам. Альтернативный подход - хранить связанную информацию вместе.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...