Reputation: 190
I have a 2D array in perl. I want to delete all elements which has the pattern <<< or >>>. I have written a perl code, it works good till matching pattern, however it cannot delete that element, some error occurs.
foreach my $x(@array)
{
foreach my $y(@$x)
{
if($y =~ (m/^(\<+)|(\>+)$/ig))
{
delete $y;
}
}
}
Can you help me to delete that particular element that matches the pattern. (I want to delete and remove from array, not undef it)
Upvotes: 2
Views: 7359
Reputation: 107090
Let's say your array looks like this:
1 2 3 4
5 X 6 7
8 9 A B
You want to delete X
. What do you want to happen? What should your new array look like after the delete?
Do you wan this:
1 2 3 4
4 6 7
8 9 A B
Or this?
1 2 3 4
5 9 6 7
8 A B
That's the first thing you need to decide. Second, you can't use delete
. The delete
command deletes a keyed value from a hash and not an array. If you have an array like this:
my @array = qw(0 1 2 3 4 5 X 7 8 9);
And you want to delete the X
(which is $array[6]
), you'd use the splice
command:
splice @array, 6, 1;
Finally, Perl does not have 2 dimensional arrays, so you can't delete a value from a 2 dimensional array.
What you have is an array of references to a second array. Think of it this way:
my @row0 = qw(1 2 3 4);
my @row1 = qw(5 X 6 7);
my @row2 = qw(8 9 A B);
my @two_d_array = (\@row0, \@row1, \@row2);
Or, I could do this by column:
my @col0 = qw(1 5 8);
my @col1 = qw(2 X 6);
my @col2 = qw(2 6 A);
my @col3 = qw(4 7 B);
my @two_d_array = (\@col0, \@col1, \@col2, \@col3);
When you talk about.
if ( $two_d_array[1][1]` eq "X" ) {
What is going on is that Perl is messing with your mind. It is making you think there's a two dimensional array is involved, but it's not really there.
A more accurate way of writing this would be:
if ( ${ $two_d_array[1] }[1] eq "X" ) {
or, more cleanly:
if ( $two_d_array[1]->[1] eq "X" ) {
So first, decide what you mean by deleting a value. In a two dimensional array, if you actually delete that value, you end up ruining the dimensional structure of that array. Maybe you can replace the value at that point with an undef
.
Once you do that, you must understand what you're actually dealing with: An array of references to arrays.
for my $array_reference ( @two_d_array ) {
for my $value ( @{ $array_reference } ) {
if ( $value =~ /^(<+|>+)$/ ) {
$value = undef; #See Note #1
}
}
}
Note #1: When you use a for loop, the index of the array is a link to the actual value in the array. Therefore, when you change the index, you're changing the actual value. That's why this will work.
If you really, really want to delete the element using splice
, you will have to decide if you want your elements moving up to replace the deleted value or moving to the left to replace the deleted value. If you want the values to the moving left, you want an array or references to row arrays. If you wan the values moving up to fill in the deleted value, you want an array of reference to column arrays.
Remember that computers will do exactly what you tell them to do and not what you want them to do. Make sure you understand exactly what you want.
Upvotes: 4
Reputation: 67930
You are applying delete
on a scalar value, $y
, and delete is only meant to be applied to hashes and arrays. You would need to do do
for my $x (0 .. $#array) {
for my $y (0 .. $#{$array[$x]}) {
if (...) { delete $array[$x][$y]; }
The best solution, in my opinion, is to remove the value before storing it in the array. I am guessing you read it in from some data source such as a file, and that would be the best place to filter it out. E.g.
while (<$fh>) {
....
@values = grep !/^[<>]+/, @values; # filtering
push @array, \@values; # storing
}
On that note, you can also do it afterwards, of course, with something like:
for (@array) {
@$_ = grep !/^[<>]+/, @$_;
}
Upvotes: 2
Reputation: 98118
delete
does not alter array indices so it is not what you want. If you want to delete elements by value, use something like this:
foreach my $x(@array)
{
$x = [ grep { $_ !~ (m/^(\<+)|(\>+)$/ig)} @$x ];
print join(",", @$x), "\n";
}
or, use splice. But then you will need to iterate the array using indices rather than values.
Also see Perl-delete, Perl-splice.
Upvotes: 0
Reputation: 2501
You can delete elements from arrays, by splice function:
splice(@array, $index, 1);
1 in this example is number of elements, you want to delete
delete
function only sets array value to undef
Upvotes: 1