in reply to I hate nested loops
To me, for idiomatic clarity I find the original nesting of for/foreach loops to be superior. The Algorithm::Loops method was initially less familiar to me, but once I put it to use it became very legible, and I imagine it would be even to someone who hadn't read the Algorithm::Loops documentation.
The slice method is a little less legible to me. I use slices all the time, but there's just something about how it plays out that makes it less than obvious at first glance what it going on. Reading through it a little more carefully, it's easy enough to understand, but it's not a segment of code that, to me at least, screams "This is what I do." However, it has the advantage of being the most computationally efficient solution, which I'll demonstrate in a moment.
For good measure I played with a nested map option too. I find it fairly easy to read; seeing the keyword map twice, and one buried inside of brackets tells me they're nested.
I was kind of hesitant to post this as it might motivate people jump to computational efficiency as a means of driving coding decisions, when maintainability and clarity probably ought to take the driver's seat unless there is a known issue. So look at the following from the perspective of already having determined that you've got a bottleneck.
use warnings; use strict; use Benchmark qw/cmpthese/; use Algorithm::Loops qw/NestedLoops/; use Test::More 'no_plan'; my @outer = ( 'aa' .. 'jj' ); my @inner = ( 'AA' .. 'JJ' ); my $count = 100; my $control = \&sliced; foreach my $compare ( \&for_each, \&nested_loops, \&mapped ) { is_deeply( $compare->( \@outer, \@inner ), $control->( \@outer, \@inner ), "Control matched." ); } cmpthese( $count, { foreach => sub{ my $res = for_each( \@outer, \@inner ) }, NestedLoops => sub{ my $res = nested_loops( \@outer, \@inner ) }, mapped => sub{ my $res = mapped( \@outer, \@inner ) }, sliced => sub{ my $res = sliced( \@outer, \@inner ) }, } ); sub for_each { my %hash; foreach my $out ( @{ $_[0] } ) { foreach my $in ( @{ $_[1] } ) { $hash{$out}{$in} = 1; } } return \%hash; } sub nested_loops { my %hash; NestedLoops( [ $_[0], $_[1] ], sub { $hash{ $_[0] }{ $_[1] } = 1; } ); return \%hash; } sub mapped { my %hash = map{ $_ => { map { $_ => 1 } @{ $_[1] } } } @{ $_[0] }; return \%hash; } sub sliced { my %hash; @{ $hash{$_} }{ @{ $_[1] } } = (1) x @{ $_[1] } for @{ $_[0] }; return \%hash; }
That produced the following results:
ok 1 - Control matched. ok 2 - Control matched. ok 3 - Control matched. Rate NestedLoops mapped foreach sliced NestedLoops 5.17/s -- -89% -91% -95% mapped 49.0/s 848% -- -19% -49% foreach 60.2/s 1065% 23% -- -37% sliced 96.2/s 1760% 96% 60% -- 1..3
Dave
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^2: I hate nested loops
by BrowserUk (Patriarch) on Aug 11, 2011 at 18:38 UTC |