Поскольку вы знаете, что массив отсортирован, есть только 1 значение, с которым вам нужно сравнивать в любой момент времени, поэтому вы можете сделать это:
my @ar = (1,2,10,3,5);
@ar = sort {$a <=> $b} @ar;
my @inverse = do {
my $i = 0;
grep { $_ != $ar[$i] or (++$i, 0) } 1 .. $ar[-1]
};
Как написано здесь, вам не нужна проверка на $i
, выходящую из конца массива, потому что диапазон заканчивается на $ar[-1]
. Если вы измените это условие, то вам нужно будет проверить $i > $#ar
или просто нажать N + 1 на @ar
перед вычислением обратного значения и вывести его потом (где N - максимальное значение диапазона). Этот код также предполагает, что в массиве не будет повторяющихся значений.
Я решил сравнить ведущих кандидатов, используя 5000 чисел от 1 до 10 000:
use 5.010;
use Benchmark 'cmpthese';
my (@orig, %used);
while (@orig < 5000) {
my $rand = 1 + int rand 10000;
push @orig, $rand unless $used{$rand}++;
}
my @ar = sort {$a <=> $b} @orig;
cmpthese(-3, {
sorted => sub {
push @ar, 10001;
my @inverse = do {
my $i = 0;
grep { $_ != $ar[$i] or (++$i, 0) } 1 .. 10000
};
pop @ar;
},
unsorted => sub {
@ar = sort {$a <=> $b} @orig;
push @ar, 10001;
my @inverse = do {
my $i = 0;
grep { $_ != $ar[$i] or (++$i, 0) } 1 .. 10000
};
pop @ar;
},
hash => sub {
my %have = map {$_ => 1} @ar;
my @inverse = grep {not $have{$_}} 1 .. 10000;
},
smartmatch => sub {
my @inverse = grep { ! ($_ ~~ @ar) } 1 .. 10000;
},
});
На Perl 5.10.1 я получил:
Rate smartmatch hash unsorted sorted
smartmatch 0.708/s -- -100% -100% -100%
hash 180/s 25279% -- -7% -67%
unsorted 193/s 27183% 8% -- -65%
sorted 551/s 77745% 207% 185% --
Как видите, многократное умное сопоставление с массивом медленное . Мой подход примерно такой же скорости, как и подход на основе хеша, если вы включите время, необходимое для сортировки @ar
. Если вы игнорируете это (возможно, вам придется сортировать @ar
в любом случае по другим причинам), то мой подход примерно в два раза быстрее, чем хеш.