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

Dereferencing hashrefs

by schnarff (Acolyte)
on Feb 11, 2002 at 01:31 UTC ( [id://144550]=perlquestion: print w/replies, xml ) Need Help??

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

After extensively searching the web on the matter, I've found that there's a lot of conflicting information on how to best take a reference to a hash and convert it into an actual, normal hash. I'm hoping you all can clear this up for me.

I've seen thing such as:
$myref = $sth->fetchrow_hashref(); my %hash = %$myref;
or
my %hash = %{$myref};
Neither of which seem to work. There have been many subtle variations on this, but I won't bore you with their details.

That all said, what is the syntatically correct way to dereference a hashref -- specifically one that's the output of DBI::fetchrow_hashref() -- into a plain, old-fashioned hash, assuming I don't know the names of the keys in the hashref? Of course, if I knew the key names, I'd just set up my new hash by looping through the reference and making a bunch of $hashref->{'keyname'} calls.

Thanks for your help.

Alex Kirk

Replies are listed 'Best First'.
Re: Dereferencing hashrefs
by rob_au (Abbot) on Feb 11, 2002 at 01:48 UTC
    The two methods which you describe above for dereferencing a hashref structure are correct as per perlref and should work.

    A couple of other debugging points which you may want to consider:

    • Are you sure that you are actually getting a return value for the DBI database query issued? If there are no matching rows or an error occurs, then fetchrow_hashref will return undef - After calling fetchrow_hashref, you should check $sth->err to ensure that the undef returned is not the result of DBI error. Alternatively, you can confirm that you are indeed having a hashref structure returned by calling ref( $myref ), the result of which should be HASH.
    • If you have no luck with examining the actual data structure returned by fetchrow_hashref as described above, you may want to paste a little bit more of your surrounding code with some comments on arguments and database structure.

     

    perl -e 's&&rob@cowsnet.com.au&&&split/[@.]/&&s&.com.&_&&&print'

      Thank you all for your responses -- they're much more than I expected.

      Since this reply seemed to have the most solid ways for checking that my fetchrow_hashref() call was working, I tried the suggestions therein. Sadly, I found that I was getting a valid hashref returned, as:
      print "Errors are: $sth->err\n"; print "I got out: ref($rec_ref)\n";
      Gives me:
      Errors are: DBI::st=HASH(0xe2478)->err I got out: ref(HASH(0xf9d14))
      both of which seem to indicate that I do, indeed, have a valid hashref to work with.

      To expand on what's going wrong, let me pull out the following bit of code from my program:
      if ($rec_ref->{'company'} ne "") { %ref = %$rec_ref; $found = 1; } $dbh->disconnect(); if ($found) { return %rec; } else { return undef; }
      I know from the database that there will *always* be a company value returned; thus, I was using that as a sanity-check that my hashref was good. From there, I set a flag on how to return from the subroutine I'm in; if it's good, I return the hash that should be filled by dereference from my hashref, otherwise undef.

      What's actuall happening here is that I *am* getting a value for $rec_ref->{'company'} (I've checked that with a print statement), and I know I'm returning a hash -- but the subroutine which uses that hash is acting as if it's empty. That subroutine is known good from other activities within my script, so I won't paste it here.

      Further comment upon this expanded code would be greatly appreciated. Again, thanks for all of your help.

      Alex Kirk
        Method calls aren't interpolated... What is the output of:
        print "Errors are: " . $sth->err . "\n";

        -Blake

        1. I notice you call your hash %ref, but return %rec - maybe this is your problem?

        2. You know $rec_ref is OK, and you know your subroutine's hash is not OK, and you know that %ref = %$rec_ref is OK (because we've told you ;-) ). So work backwards to find out where the bug is. Use perl -d and run through this subroutine, checking your hash using the "x" command, e.g. x %ref.

        dave hj~

        I'm not sure why you want to return a hash instead of a reference, but there's no need to create %ref or %rec.

        $dbh->disconnect(); return %$rec_ref unless $rec_ref->{company} eq ''; return undef;



        HTH,
        Charles K. Clarkson
        Clarkson Energy Homes, Inc.
Re: Dereferencing hashrefs
by theorbtwo (Prior) on Feb 11, 2002 at 01:46 UTC

    Both the approaches you cited (%$hashref and %{$hashref} are correct. (The {}s work like parenthesies. I've often wondered why {}s are used in this context, not ()s. Anybody?)

    What errors are you getting? Are you sure DBI::fetchrow_hashref() is returning a hashref? Clearly, it /should/, but probably returns undef on errors. Try printing out the returned value; if it is a hashref, it'll say HASH(0xyadda). (If it's a blessed hashref, it'll be Some::Class=HASH(0xyadda.)

    TACCTGTTTGAGTGTAACAATCATTCGCTCGGTGTATCCATCTTTG ACACAATGAATCTTTGACTCGAACAATCGTTCGGTCGCTCCGACGC
      The {}s work like parenthesies. I've often wondered why {}s are used in this context, not ()s.

      Curlies are used, and not parentheses, because you are actually using code blocks here. It just so happens that usually the block in question is just the contents of a scalar (which happens to be a reference to something)).

      There is nothing stopping you from putting more advanced code into that block, such as:

      for my $key( keys %{$moon->phase > 0.25 ? $thisref : $thatref} ) { ... } # or, more likely to be encountered push @{$val % 2 ? \@odds : \@evens}, $val;

      But those who come after may not always appreciate your doing so. If you really feel the urge to get fancy, consider calling a subroutine in the code block, if only to let the person drop a breakpoint on the sub so that they can follow exactly what reference is being used.

      g r i n d e r
      print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u';
      The {}s work like parenthesies. I've often wondered why {}s are used in this context, not ()s. Anybody?)

      Perl was initially based on C, sh and awk. The syntax $foo is inherited from sh, and like in sh, there were some problems if the variable was followed by a string. So, like in sh, there is the alternate syntax ${foo}.

      And then, there is the backward compatibility Perl 1 -> Perl 2 -> Perl 3 etc. This is why curlies have remained, and are still there.

      There might be another reason. There is a special variable $( ($GID), so with $(foo), there would be some ambiguous parsing. There is no special variable consisting of a dollar and a single open curly, so parsing ${foo} not ambiguous.

Re: Dereferencing hashrefs
by gav^ (Curate) on Feb 11, 2002 at 01:59 UTC
    What's wrong with just using it as a hashref? The reason it is a hashref in the first place is to save memory. You can just write things like:
    my $val = $hr->{val}; foreach my $key (keys %$hr) { # etc }
    I just don't see the need for you to create a hash from a hashref.

    gav^

Re: Dereferencing hashrefs
by blakem (Monsignor) on Feb 11, 2002 at 01:54 UTC
    I think you'll have to expand on "Neither of which seem to work" since the snippets you provided look just fine. Perhaps your DBI call is failing and you aren't checking it. This works fine for me:
    my $sth = $dbh->prepare($sql) or die "error preparing: '$sql': " . $dbh->errstr; $sth->execute() or die "error executing: '$sql': " . $dbh->errstr; my $ref = $sth->fetchrow_hashref() or die "error fetching: '$sql': " . $dbh->errstr; my %hash = %$ref; print "H: $_ => $hash{$_}\n" for keys %hash;

    -Blake

Re: Dereferencing hashrefs
by Ryszard (Priest) on Feb 11, 2002 at 01:48 UTC
    This is what I do, its a little messy, but when you get the hang of it, works quite well.
    sub db_get { .. .. # fetch the rows into an array reference while ( $retstat = $sth->fetchrow_hashref ) { push @retval, [$retstat]; } .. .. return @retval }
    To dereference it I do:
    my $value = $ary[0][0]->{<key>} # to Shorten it (so it's not so hard to type) my %short = %{$ary[0][0]};
    As I said, its messy, but it works for me.
Re: Dereferencing hashrefs
by japhy (Canon) on Feb 11, 2002 at 01:47 UTC
    Sorry, but you've got it right with the syntax. How isn't it working for you?

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who could use a job
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://144550]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (2)
As of 2024-04-24 23:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found