Это похоже на некоторый C-код с синтаксисом Perl. Иногда знание языка, на котором думает человек, помогает понять, что происходит. В этом случае мозг человека заражен внутренними механизмами управления памятью, арифметикой указателей и другими проблемами низкого уровня, поэтому он хочет тщательно контролировать все:
my @selected_heads = ();
# a tricky way to make a two element array
for my $i (0..1) {
# choose a random file
$selected_heads[$i] = int rand @heads;
# for all the files (could use $#heads instead)
for my $j (0..@heads-1) {
# stop if the chosen file is not already in @selected_heads
# it's that damned ! in front of the grep that's mind-warping
last if (!grep $j eq $_, @selected_heads[0..$i-1]);
# if we are this far, the two files we selected are the same
# choose a different file if we're this far
$selected_heads[$i] = ($selected_heads[$i] + 1) % @heads; #WTF?
}
...
}
Это большая работа, потому что оригинальный программист либо не понимает хэши, либо не любит их.
my %selected_heads;
until( keys %selected_heads == 2 )
{
my $try = int rand @heads;
redo if exists $selected_heads{$try};
$selected_heads{$try}++;
}
my @selected_heads = keys %selected_heads;
Если вы все еще ненавидите хеши и используете Perl 5.10 или более позднюю версию, вы можете использовать smart-match, чтобы проверить, есть ли значение в массиве:
my @selected_heads;
until( @selected_heads == 2 )
{
my $try = int rand @heads;
redo if $try ~~ @selected_heads;
push @selected_heads, $try;
}
Однако у вас есть особое ограничение на эту проблему. Поскольку вы знаете, что есть только два элемента, вам просто нужно проверить, является ли элемент, который вы хотите добавить, предшествующим элементом. В первом случае это не будет undef, поэтому первое дополнение всегда работает. Во втором случае он просто не может быть последним элементом в массиве:
my @selected_heads;
until( @selected_heads == 2 )
{
my $try = int rand @heads;
redo if $try eq $selected_heads[-1];
push @selected_heads, $try;
}
Ха. Я не могу вспомнить, когда в последний раз я использовал until
, когда это действительно соответствовало проблеме. :)
Обратите внимание, что все эти решения имеют проблему, заключающуюся в том, что они могут вызывать бесконечный цикл, если число исходных файлов меньше 2. Я бы добавил условие защиты выше, чтобы в случае отсутствия и одиночного файла возникала ошибка возможно, дело о двух файлах не стоит их заказывать.
Другой способ сделать это - перемешать (скажем, с помощью List :: Util ) весь список оригинальных файлов и просто удалить первые два файла:
use List::Util qw(shuffle);
my @input = 'a' .. 'z';
my @two = ( shuffle( @input ) )[0,1];
print "selected: @two\n";