Re: can't remove all zeroes from an array
by GrandFather (Saint) on Aug 09, 2007 at 08:25 UTC
|
The problem is that as you remove elements you invalidate the index that you are using. However, Perl has a much better way of doing what you want. Consider:
use strict;
use warnings;
my @arry = (9,0,0,5,3,0,0,0,2,0,1,0);
print "@arry \n";
@arry = grep {$_} @arry;
print "@arry \n";
Prints:
9 0 0 5 3 0 0 0 2 0 1 0
9 5 3 2 1
The magic is grep.
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by johngg (Canon) on Aug 09, 2007 at 09:06 UTC
|
GrandFather has pointed out the best solution to your problem using grep and the reason why your code was failing. However, it is sometimes a useful technique, when doing something that might invalidate an index, to consider working back from the end of the array to the beginning. That way you can avoid mucking the index up.
use strict;
use warnings;
my @arr = (9, 0, 0, 5, 3, 0, 0, 0, 2, 0, 1, 0);
print qq{@arr\n};
for my $idx ( reverse 0 .. $#arr )
{
splice @arr, $idx, 1 unless $arr[$idx];
}
print qq{@arr\n};
This produces
9 0 0 5 3 0 0 0 2 0 1 0
9 5 3 2 1
I hope this is useful. Cheers, JohnGG | [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by Beechbone (Friar) on Aug 09, 2007 at 08:41 UTC
|
When your code removes a 0, another element of the array will slide into that slot---but your code will move on to the next slot and will not check that element. So if there are 2 0s in a row, it will check and remove the first 0 and ignore the second 0 because that now is at a position where the first 0 was already removed.
BTW: This is exactly the same kind of problem a for loop will run into if you change the array it is running over. So remember the old rule to never change an array you're iterating over unless you know exactly what you are doing.
Your algo is not that far of, just put the $i++ in an else block. (Or use a more perlish way, see the othe reply.)
| [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by ikegami (Patriarch) on Aug 09, 2007 at 12:55 UTC
|
The smallest change needed to fix your code is to only increment $i when you don't remove an element.
while ( $i <= $#arry)
{
if ($arry[$i] == 0)
{splice @arry, $i,1;}
else
{$i++;}
}
| [reply] [d/l] [select] |
|
|
$i = @arry;
while ( --$i >= 0 )
{
if ($arry[$i] == 0)
{splice @arry, $i,1;}
}
| [reply] [d/l] |
Re: can't remove all zeroes from an array
by FunkyMonk (Bishop) on Aug 09, 2007 at 08:50 UTC
|
Consider what happens before the splice, when $i is 1:
- Before the splice:
9,0,0,5,3,0,0,0,2,0,1,0
^ $i is 1
- After the splice:
9,0,5,3,0,0,0,2,0,1,0
^ $i is 1
$arry[$i] is still 0
You need to keep spliceing while it remains zero, change your if to a while.
Now think about what happens when you've just spliced that last 0. $i points past the end of the array, so you need to add a check for that into the while condition:
while ( $i <= $#arry && $arry[$i] == 0 )
Having said all of that, GrandFather is right. Just use grep.
| [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by Anno (Deacon) on Aug 09, 2007 at 09:34 UTC
|
As has been noted, the standard solution would be to use grep().
The problem you encountered with splice() is very common: Splicing elements in or out of a list upsets the numbering of the remaining elements. Often the solution is to traverse the list in reverse order, beginning at the high end. Thus, splice can be used much in the way you originally had it:
my $i = $#arry;
while ( $i >= 0 )
{
if ($arry[$i] == 0)
{splice @arry, $i,1;}
$i-- ;
}
or, more compact:
$arry[ $_] or splice @arry, $_, 1 for reverse 0 .. $#arry;
Anno | [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by swampyankee (Parson) on Aug 09, 2007 at 14:29 UTC
|
@array = (1, 0, 2, 0, 3, -1, 0, 4, 0, -5, 0, 123);
@nonzeros = grep {$_} @array;
or
@array = (1, 0, 2, 0, 3, -1, 0, 4, 0, -5, 0, 123);
@nonzeros = grep {$_ != 0} @array;
Both are based on the assumption that the array's contents are strictly numeric; if you want to remove strings, your grep would require a different regex.
emc
Information about American English usage here and here.
Any New York City or Connecticut area jobs? I'm currently unemployed.
| [reply] [d/l] [select] |
Re: can't remove all zeroes from an array
by Praveen (Friar) on Aug 09, 2007 at 11:23 UTC
|
my @arry = (9,0,0,5,3,0,0,0,2,0,1,0);
print "@arry \n";
@new_ary = grep{/[^0]/} @arry;
print "@new_ary \n";
| [reply] [d/l] |