Re: Foreach syntax
by kyle (Abbot) on Jul 25, 2008 at 16:10 UTC
|
for my $p9 ( grep { $is_available{$_} } keys %is_available ) {
If you want it efficient:
for my $p9 ( keys %is_available ) {
next if ! $is_available( $p9 };
Which one of those is faster will probably depend on how many items get filtered out for looping. The grep is a loop in itself, so that solution actually loops twice with the second loop being "shorter"—depending on how many are filtered out. I expect grep to be a faster loop than the for, however, so that might still be a speed increase—depending on how many are filtered out.
All that's more or less irrelevant, however, until profiling your code shows that this is an issue. There's no need to make it faster until you're sure it's what's slowing you down. | [reply] [d/l] [select] |
|
|
If you want it efficient...
... then use unless instead of the silly if !, as it's more efficient when parsing to only do one state machine transition instead of two.
(Finally, an argument that the kind of people who think unless is EHORRIBLEAWFULEVILALWAYSANDFOREVER are likely to accept!)
| [reply] [d/l] [select] |
|
|
EHORRIBLEAWFULEVILALWAYSANDFOREVER
Can we please have that error value reported by Parrot when it sees if ! ... or if not ... coded?
And for any ludicrously large memory requests, how about EBYGUM?
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
Re: Foreach syntax
by FunkyMonk (Bishop) on Jul 25, 2008 at 16:06 UTC
|
my %is_available = ( zero => 0, one => 1, two => 2 );
for my $p9 ( grep { $is_available{$_} } keys %is_available ) {
print $p9;
}
| [reply] [d/l] |
|
|
I personally believe that for the benefit of the OP it would be sensible to explain that while this does exactly what he asked for: namely "select" non zero values within the C<for> clause, it would be "inefficient" (in some sense) in that grep is a loop in disguise. Thus with such code one is iterating twice over... well, not just the same list, but two strictly correlated ones. Literally, it's like one had been doing:
my @nonzero;
for (keys %is_available) {
push @nonzero, $_ if $is_available{$_};
}
for my $p9 ( @nonzero ) {
print $p9;
}
| [reply] [d/l] [select] |
Re: Foreach syntax
by pjotrik (Friar) on Jul 25, 2008 at 16:10 UTC
|
for my $p9 ({grep($is_available{$_}} keys %is_available)) {
...
But, personally, I prefer:
for my $p9 (keys %is_available) {
next unless $is_available{$p9};
...
I find it more readable, and it should be more efficient as well, as you don't create another array. | [reply] [d/l] [select] |
|
|
Thanks to all. You guys rock!
| [reply] |
Re: Foreach syntax - don't forget the each function!
by Narveson (Chaplain) on Jul 25, 2008 at 21:06 UTC
|
Any time you find yourself looking up a hash value for each key of a hash, don't forget the appropriately named each function.
while (my ($p9, $is_available) = each %is_available) {
next if !$is_available;
# do something with each available $p9
}
The foreach (keys) iteration walks through the hash but averts its eyes from the values. The while (($key, $value) = each) iteration sensibly says we may as well grab the value while we're in the neighborhood.
| [reply] [d/l] [select] |
|
|
Always think twice before using each. If you exit the loop early the iterator will not be reset if you enter the loop again:
my %hash = qw/ one 1 two 2 three 3 four 4 five 5 /;
print "pass 1-----\n"; once_thru();
print "pass 2-----\n"; once_thru();
sub once_thru {
while ( my ( $k, $v ) = each %hash ) {
last if $k eq 'five';
print "$k $v\n";
}
}
__END__
pass 1-----
three 3
pass 2-----
one 1
two 2
four 4
From each:
There is a single iterator for each hash, shared by all "each", "keys", and "values" function calls in the program; it can be reset by reading all the elements from the hash, or by evaluating "keys HASH" or "values HASH".
The pitfalls could be made much clearer, IMHO.
| [reply] [d/l] |
Re: Foreach syntax
by apl (Monsignor) on Jul 25, 2008 at 16:12 UTC
|
This is untested, but it should work:
my @used = grep( %is_available{ $_ } ) keys( %is_available );
for my $p9 ( @used ) {
# use $is_available{ $p9 };
Revised: FunkyMonk and blazar both believe I'm farblondzhet, so I do apologize and strike my response...
| [reply] [d/l] |
|
|
This is untested, but it should work:
I personally believe that you should test it then, since (we're not under Perl 6 yet and) the %is_available{ $_ } form of subscripting/slicing doesn't exist! Incidentally, I wish it did, but... for something completely different!
| [reply] [d/l] [select] |