Stepping through an array and making changes "as-you-go" has unforeseen problems.
We get quite a few "Why didn't this work?" questions related directly to attempting to do this type of thing.
The issue is actually documented in "perlsyn: Foreach Loops" and specifically mentions splice:
"If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that."
[In case you didn't know, for and foreach are synonymous.]
So, you'd need to do something like the following.
sub splice_unique2 {
my @sorted = sort qw{q w e r t y q w e r t y};
my $last = '';
my @unique = @sorted;
my $removed = 0;
for (0 .. $#sorted) {
if ($sorted[$_] eq $last) {
splice @unique, $_ - $removed++, 1;
}
else {
$last = $sorted[$_];
}
}
}
I plugged that in to my earlier benchmarking script.
Here's a representative result:
Rate splice_unique2 splice_unique shift_unique
+map_unique
splice_unique2 83836/s -- -10% -15%
+ -28%
splice_unique 92839/s 11% -- -6%
+ -20%
shift_unique 99211/s 18% 7% --
+ -14%
map_unique 115924/s 38% 25% 17%
+ --
My coding of splice_unique2() was really just intended to show a way to get around the documented issue.
If you think the task has any merit, feel free to try to rewrite it to run faster.
|