Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Making hashes from arrays

by CodeJunkie (Monk)
on May 22, 2003 at 23:01 UTC ( #260274=perlquestion: print w/replies, xml ) Need Help??

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

I have the following sub routine and I want to make it more efficient, or at least less lines of code. I'm sure there must be a better way of achieving the same effect with some clever perl 'one liner'!!!!

Ok, here's my code.

sub getHallDetails() { my ($hall_id,$dbh)=@_; my $sth=$dbh->prepare("select hall_name,upload_date,uploaded_by,phot +o_id from hall_details where hall_id='$hall_id' limit 1;"); $sth->execute(); my %hall_details=(); while (my ($hall_name,$upload_date,$uploaded_by,$photo_id) = $sth->f +etchrow_array()) { $hall_details{$hall_id}{hall_id}=$hall_id; $hall_details{$hall_id}{hall_name}=$hall_name; $hall_details{$hall_id}{upload_date}=$upload_date; $hall_details{$hall_id}{uploaded_by}=$uploaded_by; $hall_details{$hall_id}{photo_id}=$photo_id; } return %hall_details; }

It's not great I realise this, how can I reduce the number of lines I am typing here?

Thanks, your advice is greatly appreciated,

Replies are listed 'Best First'.
Re: Making hashes from arrays
by theorbtwo (Prior) on May 22, 2003 at 23:08 UTC

    Yes, there is a better way to do this, but it doesn't have to do with not knowing your perl, but rather your DBI. You want fetchrow_hashref.

    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Making hashes from arrays
by Zaxo (Archbishop) on May 23, 2003 at 00:09 UTC

    Just a couple of other points.

    Your statement handle would benefit from placeholders, and forming a closure for the prepared handle would allow the prepare call to only be done once:

    # after $dbh is obtained { my $sth = $dbh->prepare "select hall_name, upload_date, uploaded_by, photo_id from hall_details where hall_id=? limit 1"; sub details_from_id { my $id = shift; $sth->execute $id; $sth->fetchrow_hashref; } # mod some error checking }
    With that, you get the the advantages of global variables without some of the headaches. The DBI handle could itself be encapsulated this way. Is hall_id the primary key? If so the limit clause can be omitted.

    The other point is that your returned hash is a level too deep. The caller already knows $hall_id - it was passed as an argument - and will just need to extract the lone value from your return. With that, you can just call details_from_id directly.

    my @hall_ids = 1..20; my %details; @details{@hall_ids} = map { details_from_id $_ } @hall_ids;

    After Compline,

      Or couse, the limit assuming postgres or mysql ( or other non-Oracle type stuff )...
Re: Making hashes from arrays
by BrowserUk (Pope) on May 22, 2003 at 23:15 UTC

    Untested and broken (see Abigail-IIs post below), but I think your while loop could be replaced by

    1 while @hall_details{$hall_id}{ qw[ hall_id hall_name upload_date uploaded_by photo_id ] } = $sth->fetchrow_array();

    Update: I should never post untested code. It always bites me. Again, I think this would work.

    my @fields; @( hall_details{$hall_id} }{ qw[ hall_id hall_name upload_date uploaded_by photo_id ] } = @fields while @fields = $sth->fetchrow_array();

    which would save a lot of typing and to the offense of the "it don't matter how long it takes brigade", it might even be slightly more efficient:) Feel free to reformat that however suits your view of beauty.

    That said, I have a sneaky suspicion that you can ask DBI to return the data as a hash to begin with, which would undoubtably be your best option.

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
      That doesn't look right, even after fixing the syntax error. Since you call $sth -> fetchrow_array () until it returns an empty list, the last assignment will be the equivalent of:
      @{$hall_details {$hall_id}} {qw [ ... ]} = ();

      Effectively wiping out the content the OP was interested in.


Re: Making hashes from arrays
by nite_man (Deacon) on May 23, 2003 at 07:10 UTC
    I think that you can use DBI method fetchall_arrayref() for fetching all records set in one time as array reference on array references rows:
    sub getHallDetails() { my ($hall_id, $dbh) = @_; my $sth=$dbh->prepare("select hall_name, upload_date, uploaded_by, p +hoto_id from hall_details where hall_id='$hall_id' limit 1;"); $sth->execute(); my $res_arr = $sth->fetchall_arrayref(); $sth->finish; my $hall_details={ $hall_id => $res_arr }; return $hall_details; }
    SV* sv_bless(SV* sv, HV* stash);
Re: Making hashes from arrays
by wufnik (Friar) on May 23, 2003 at 07:56 UTC
    building on the fine work by nite man here is something that deaks with your initial array of hall_ids too. i use @constrings here for clarity not efficiency, or memory management...

    # presume dbh hunky dory my @hall_ids = ("slumber1", "slumber2", "slumber3"); my %hall_details; my @constrings = map { "select hall_name, upload_date, uploaded_by, photo_id " . "from hall_details where hall_id='$_' limit 1;" } @hall_ids; map { my $sth = $dbh->prepare($constring[$_]); $sth->execute(); $halldetails{$hallid[$_]} = $sth->fetchall_arrayref(); $sth->finish(); } (0 .. $#hallids);

    -- in the world of the mules there are no rules --

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://260274]
Approved by broquaint
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2020-05-26 12:37 GMT
Find Nodes?
    Voting Booth?
    If programming languages were movie genres, Perl would be:

    Results (150 votes). Check out past polls.