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

Although this seems like the eternal question, as there are many variations on this problem posted on PM, some of which include Benchmarks, I've just found something a little curious when it comes to benchmarking two approaches to this.

I'm converting a 2xn array reference, which is the result of a DBI call (selectall_arrayref), into a hashref. At first, I thought the easy way might be to do something like:
sub AssembleByHash { my ($array_ref) = @_; my (%result); foreach my $row (@$array_ref) { $result{$row->[0]} = $row->[1]; } return \%result; }
Which I thought would be far to easy, since it didn't harness the Power of Map. So, instead, I supposed that this might be faster:
sub AssembleByArray { my ($array_ref) = @_; my (%result); %result = map { @$_ } @$array_ref; return \%result; }
After all, it's quick and to the point. When applying Benchmark to validate my theory, though, I got the following result using a 10_000 row test-table and 100 iterations:
Benchmark: timing 10 iterations of AssembleByArray, AssembleByHash... AssembleByArray: 10 wallclock secs ( 9.64 usr + 0.04 sys = 9.68 CPU) + @ 1.03/s (n=10) AssembleByHash: 1 wallclock secs ( 1.31 usr + 0.00 sys = 1.31 CPU) +@ 7.63/s (n=10) Rate AssembleByArray AssembleByHash AssembleByArray 1.03/s -- -86% AssembleByHash 7.63/s 639% --
So, I can only suppose that the temporary array created by the map call is killing performance. Or, am I missing something?

Replies are listed 'Best First'.
Re: Multi-Dimensional Array to Hash Conversion Optimization
by MeowChow (Vicar) on Apr 03, 2001 at 20:21 UTC
    There is a performance issue in Perl 5.6 which causes it to take quadratic time for returning multiple list values in map calls, though tilly has produced a patch for this.

    For more detail on this issue, check out this thread.

       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
(boo) Re: Multi-Dimensional Array to Hash Conversion Optimization
by boo_radley (Parson) on Apr 03, 2001 at 20:39 UTC
    Huh? why not use
    $ary_ref = $dbh->selectall_hashref($statement);
    don't make things harder than they need to be! :)
      Perhaps because of this:      Can't locate object method "selectall_hashref" via package "DBI::db" at test line 5. Update: It would seem that, as boo_radley pointed out below, there is an upgrade to DBI. Jumped the gun there, I guess, if only because I've assumed that such a thing existed before only to find run-time errors. (Heh, oops) Thanks for the explanation! That puts the stuff below into a pseudo-historical context then...

      I'm hoping that some day they will implement one. However, the idea was that I wanted to take an array containing (key,value) pairs inside their own ARRAY-ref and convert back.

      I had cooked up something like this before:
      sub selectall_hashref_byid { my ($table) = shift; my ($select); if (scalar(@_) == 1) { # Single key to fetch, so no HoH return { @{$db->selectall_arrayref("SELECT id,? FROM $ +_", $_[0])} }; } if (@_) { unshift (@_, 'id') unless (@_ && grep ("id", @_)); } else { @_ = ('*'); } my ($hash, $row, $query); $hash = {}; $query = $db->prepare ("SELECT ".join (',', @_)." FROM $table" +); $query->execute (); while (my $row = $query->fetchrow_hashref) { # Stoke it $hash->{$row->{id}} = $row; # Deredundantize it delete $hash->{$row->{id}}->{id}; } return $hash; }
      The only downside is that the crazy casting that goes on in there doesn't handle errors very well, so it is really flying by the seat of your pants.
        *smacks head*
        not everyone upgrades as rapidly as you do, boo...
        If you can, hie thee unto cpan:
        Changes in DBI 1.15, 28th March 2001 ... Added selectall_hashref thanks to Leon Brocard. ...