| [reply] [d/l] |
If you are always going to be accessing arbitrary rows and columns, not whole rows at once, you could consider using perl4's emulated multidimensional arrays (see $;), like so:
my %matrix;
$matrix{0,0} = 1;
$matrix{0,1} = 0;
$matrix{1,1} = 1;
$matrix{1,0} = 0;
Then copying is just a matter of saying my %new_matrix = %$matrix_ref;
| [reply] [d/l] [select] |
In my code, 2D arrays are arrays of references to arrays (any other way to implement them?).
The answer to the question is "yes", but I wouldn't use any of the ways I can think of implementing 2D arrays other than having arrays of references to arrays.
When i pass a matrix to a subroutine, i pass the subroutine a reference to the matrix (also, any other way to pass such a 2D array?).
Yes, you could use a package variable for your array, and pass a glob. But that's very Perl4ish, and buys you little in Perl5; beside from that, people will have a harder time understanding your code. Passing a reference is the standard way.
And since efficiency is quite a concern to me, i am trying to know if there's a better, more efficient way to dereference a 2D array and modify the new array without affecting the original one.
It depends. If the sub you call is supposed to return a new, completely different array, the values have to be copied one way or another. I'd write it different though:
sub foo {
my $array = shift;
my $copy = [map {[@$_]} @$array];
... Changes in $copy won't affect $array ...
return $copy;
}
You may be able to speed it up by doing the copying in XS (or use a module that does so), but it still scales lineary with the number of elements in $array.
However, if you only need to make changes in the array in the subroutine, and don't need the changes when the sub is done, you could use local when modifying the array. No initial copy is needed.
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
use YAML;
sub foo {
my $array = shift;
local $array->[0][1] = "bar";
print Dump $array;
}
my @array = ([1, 2, 3], [4, 5, 6],);
foo \@array;
print Dump \@array;
__END__
---
-
- 1
- bar
- 3
-
- 4
- 5
- 6
---
-
- 1
- 2
- 3
-
- 4
- 5
- 6
As you can see, $array[0][1] has a different value in foo, but outside the sub, @array is unmodified. | [reply] [d/l] [select] |
Thank you very much for the elaborate reply. As you noted in your reply, the subroutines do return a new, completely different array. In that case, you mentioned:
"the values have to be copied one way or another. I'd write it different though:
sub foo {
my $array = shift;
my $copy = [map {[@$_]} @$array];
... Changes in $copy won't affect $array ...
return $copy;
}
As i can see, now $copy is a reference that points to an array of (a new set of) references, each of which contain the same elements as the corresponding reference in @original_array. It could be written in this way though.
sub foo {
my $array = shift;
my @copy = map {[@$_]} @$array;
... Changes in @copy won't affect @array ...
return \@copy;
}
right?
And is the reason that you'd copy the elements this way is that it's faster?
Again, thanks a lot for your tips,
Hadi
| [reply] [d/l] [select] |
Yes, you can write it with @copy and returning it as \@copy. But I prefer using $copy, for symmetrical reasons. I start out with a reference to an array, so if I copy it, I'd like to copy to another reference. But that's just personal preference, I don't one way is significantly faster or easier to understand than the other.
As for copying using a map instead of the double loop is mostly because it's less verbose. It's just one line and I see immediately it's a copy of a 2D array - the double loop takes more lines, and too large to immediately see what it does. I haven't benchmarked it, but if there's a difference I expect the difference to be small, and the map to be slightly faster; with the difference slowly growing if the arrays get larger. But speed isn't my main reason to copy it using a map.
| [reply] |