Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Is there a difference between these two styles? Is there an advantage one way?
$mysql = $dbh->exec ( $sql ); for (my $i = 0; $i < @{$mysql}; $i++) { my $field1 = $mysql->[$i]{‘field1’}; my $field2 = $mysql->[$i]{‘field2’}; or… $mysql = $dbh->exec ( $sql ); foreach (@$mysql) { my $field1 = $_->{ ‘field1’ }; my $field2 = $_->{ ‘field2’ };

Thanks for looking!

Replies are listed 'Best First'.
Re: Style and Preference on Loops
by cdarke (Prior) on Aug 12, 2011 at 15:16 UTC
    The first style, the C style counting loop, requires that you maintain your own iterator ($i), ensure it is always incremented, and check the bounds of the array. With the second loop, perl does all that for you.

    I expect the second is more efficient, although I have never measured it and I doubt the difference is huge, but I prefer the second because of two principles:

    1. Less code generally means fewer bugs.
    2. Why have a dog and bark yourself?
Re: Style and Preference on Loops
by TomDLux (Vicar) on Aug 12, 2011 at 19:34 UTC

    If you're on a Unix/Linux/Mac, type perldoc perl into a terminal window, and see all the documentation you already have installed on your machine. ( I dunno how to view it on MSDos, but I'd try typing the same thing in a cmd shell. ) or you can go to CPAN or ask google to find 'perl pod'. perlsyn is the section which actually discusses syntax.

    Briefly, there is almost never a reason to use the C style for loop. If you want to iterate over a list, let Perl handle the hard part:

    for my $elem ( @$mysql ) { my $field1 = $elem->{field}; }

    If you want to keep track of the index number, use the range operator, let Perl handle the hard part:

    for my $idx ( 0..@$mysql ) { my $field1 = $mysql->[$idx]{field1}; }

    Notes: If you specify an array in a scalar context, Perl decides you want to know how many elements there are in the array. The range operator is definitely a scalar context, it expects a number on the left and a number on the right. I frequently use scalar @array, so others will decipher what I'm doing more easily; some people think the superfluous 'scalar' is bad ( Hi Mike ).

    Some people differentiate between 'for' and 'foreach'; they must love typing. I use 'for' for both, since Perl considers them synonyms.

    You don't need to quote hash tags, you can use the bare text; similarly, the bare characters before a fat arrow are automatically taken as a string:

    use 5.010; $tag = 'Homer'; my %h = ( $tag => 'woohoo!', Fred => 'YABA DABA DOO!' ); say Dumper(\%h); # outputs: # $VAR1 = { # 'Homer' => 'woohoo!', # 'Fred' => 'YABA DABA DOO!' # };

    As Occam said: Entia non sunt multiplicanda praeter necessitatem.

      for my $idx ( 0..@$mysql ) {
      Of course, that should read:
      for my $idx ( 0..@$mysql-1 ) {

        No, it should read:

        for my $idx ( 0..$#$mysql ) {

        Thank you.

        As Occam said: Entia non sunt multiplicanda praeter necessitatem.

Re: Style and Preference on Loops
by VinsWorldcom (Prior) on Aug 12, 2011 at 17:09 UTC

    I use a mix of both. If I need to know the actual index in the loop for something I'm doing, the first works. If I'm just iterating over the elements and don't necessarily need to know the index, I use the second.

      Perl 5.12 added the capability for each to return the index and value of an array in list context.

      If you need to know the index and are using an increment of 1 then:

      for my $index (0 .. $#$mysql) {

      is much better than the C for loop variant. About the only time a C loop is likely to be used in Perl is when the "increment" is not 1 or the termination condition is not simply reaching an end point, although there are often better ways of achieving both objectives than using a C for loop.

      Update: $#$mysql per eyepopslikeamosquito's catch

      True laziness is hard work
Re: Style and Preference on Loops
by afoken (Chancellor) on Aug 13, 2011 at 04:13 UTC

    If you work with DBI, using a while-loop may be more efficient than reading the entire result set into memory and iterating over it using a for loop. See $sth->bind_columns() and the last paragraph in $sth->fetchall_arrayref(): A standard while loop with column binding is often faster because the cost of allocating memory for the batch of rows is greater than the saving by reducing method calls. It's possible that the DBI may provide a way to reuse the memory of a previous batch in future, which would then shift the balance back towards fetchall_arrayref().

    Try Devel::NYTProf to find out if that difference is really relevant for your application. Note that NYTProf will very likely show you the real bottlenecks in your application.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)