I was curious what the most efficient way to swap two elements in an array in Perl would be.
Say I want to switch the elements with indexes of 3 and 5 respectively, what would be the fastest way to do that?
My thoughts were something like:
@array[3,5] = @array[5,3];
Is this very efficient? My hope is that it wouldn't make a difference if those two array values contained large amounts of data. I would expect the back-end to change the pointers around, without doing any actual copying. Is that correct?
What do you mean "large amounts of data"? If you mean references to large data structures, it doesn't matter how you do it; it will be crazy fast. (Less than one nanosecond per swap.) So I'm going to assume you meant "large strings".
Before 5.20, the code you posted would copy the strings. You can avoid that using Data::Alias.
use Data::Alias;
alias @array[3,5] = @array[5,3];
Or you can do the same with a little XS if you want to avoid the syntax magic of Data::Alias:
void swap_array_elements(AV * av, IV ix1, IV ix2) {
SV ** p_ele1 = av_fetch(av, ix1, 1);
SV ** p_ele2 = av_fetch(av, ix2, 1);
SV * sv = *p_ele1;
*p_ele1 = *p_ele2;
*p_ele2 = sv;
}
Since 5.20, the string copies were replaced with a simple pointer swap.
$ 5.18t/bin/perl -MDevel::Peek -e'
my @a = qw( a b c d e f );
Dump($a[3]);
Dump($a[5]);
@a[3,5] = @a[5,3];
Dump($a[3]);
Dump($a[5]);
' 2>&1 | grep '^ PV'
PV = 0x353fba0 "d"\0
PV = 0x357abb0 "f"\0
PV = 0x3541ff0 "f"\0
PV = 0x3537940 "d"\0
$ 5.20t/bin/perl -MDevel::Peek -e'
my @a = qw( a b c d e f );
Dump($a[3]);
Dump($a[5]);
@a[3,5] = @a[5,3];
Dump($a[3]);
Dump($a[5]);
' 2>&1 | grep '^ PV'
PV = 0xe9ace0 "d"\0
PV = 0xe8f230 "f"\0
PV = 0xe8f230 "f"\0
PV = 0xe9ace0 "d"\0
This means that the straightforward @array[3,5] = @array[5,3];
will do just fine.
Running bvr's benchmark script with a modification:
my @array = ('thing' x 1E5, 'stuff' x 5E5, 'that' x 1E6, 'joe' x 5E6,
'sofa' x 1E7, 'jim' x 5E7);
Results:
Rate slice temp alias
slice 1.98/s -- -69% -100%
temp 6.47/s 227% -- -100%
alias 4218715/s 213045016% 65227727% --
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With