splice
может перейти к O (n ^ 2) в условиях, которые вы описываете (поскольку он перемещает содержимое массива), а grep
/ slice выделит O (n) дополнительной памяти (возможно, намного меньше, чем 500 ГБ,но до сих пор...).
Существует линейное решение без дополнительной памяти, но оно больше похоже на C, чем на Perl:
sub inplace_grep {
my ($code, $array) = @_;
# move elements backwards
for (my ($to, $from)=(0,0); $from < @$array; $from++) {
$code->($array->[$from]) or next;
$array->[$to++] = $array->[$from];
};
# remove tail
splice @$array, $to;
};
Обновление: при использовании памяти grep - выможет выполнить быструю проверку на выделение дополнительной памяти, используя большие объемы данных и ища системный вызов brk
.В моей системе (Linux, Perl 5.10) это так.
strace -e trace=brk perl -MTime::HiRes -wle \
'print "start ".time; my @array = 1..10**7; print "alloc ".time;
@array = grep { $_ %2 } @array; print "grep ".time'