Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re: Why is my code assigning the last-retrieved value to all elements in my hash?

by punch_card_don (Curate)
on Jul 10, 2008 at 12:51 UTC ( [id://696686]=note: print w/replies, xml ) Need Help??


in reply to Why is my code assigning the last-retrieved value to all elements in my hash?

Soooooo....Many thanks to Kyle and others for sticking with this even when I got crabby yesterday.

Really the central problem was extending a one-dimensional hash to a two-dimensional one and then expecting the first-dimension's keys to remain scalars. Having extended the original hash into a hash of hashes, clearly the first-dimension's keys had to become hash-refs.

With all due respect to Kyle, I don't believe it has anything at all to do with using "1".

The booklist_1 hash populating loop

while ($book_id = $sth->fetchrow_array()) { $booklist_1{$book_id} = 1; }
works just fine. There'd be something seriously fubar if you couldn't set the value of a variable to 1. At this point, keys %booklist_1 gives me the list of book_id's.

Where it gets messed up is in the second loop where I extend the hash

$sql = "select update_id, title from booklist_table where (book_id = ? +) order by update_id desc limit 1"; $sth = $dbh->prepare($sql) or die("Could not prepare!" . $dbh->errstr) +; foreach $book_id (keys %booklist_1) { $sth->execute($book_id) or die("Could not execute!" . $dbh->errstr +); ($update_id, $title) = $sth->fetchrow_array(); $booklist_1{$book_id}{'update_id'} = $update_id; $booklist_1{$book_id}{'title'} = $title; print "$book_id > $booklist_1{$book_id}{'update_id'}\n"; } $sth->finish;
When I extend it to two dimensions, it becomes a hash of hashes and the first dimension's keys must become references to the second dimenion hashes. So now keys %booklist_1 is a bunch of hash references, and no longer the bunch of book_ids I set them to originally. Kyle set me onto this when he wrote

You can't have a $b{foo}{bar} and have $b{foo} set to some unrelated value (such as 1). If there is a $b{foo}{bar}, then $b{foo} must somehow be a reference to a hash where you access ->{bar}.

My final solution is to use distinct hashes, like this:

$sql = "SELECT book_id FROM booklist_table WHERE (expected_publcn_date + >= '".$start_date."' AND expected_publcn_date <= '".$end_date."')"; $sth = $dbh->prepare($sql) or die("Could not prepare!" . $dbh->errstr) +; $sth->execute() or die("Could not execute!" . $dbh->errstr); while ($book_id = $sth->fetchrow_array()) { $booklist_1_temp{$book_id} = 1; } $sth->finish; $sql = "select update_id, title from booklist_table where (book_id = ? +) order by update_id desc limit 1"; $sth = $dbh->prepare($sql) or die("Could not prepare!" . $dbh->errstr) +; foreach $book_id (keys %booklist_1_temp) { $sth->execute($book_id) or die("Could not execute!" . $dbh->errstr +); ($update_id, $title) = $sth->fetchrow_array(); $booklist_1{$book_id}{'update_id'} = $update_id; $booklist_1{$book_id}{'title'} = $title; print "$book_id > $booklist_1{$book_id}{'update_id'}\n"; } $sth->finish;
Note the "_temp" added to the booklist_1 hash name in the first loop. Which works like a charm.




Time flies like an arrow. Fruit flies like a banana.

Replies are listed 'Best First'.
Re^2: Why is my code assigning the last-retrieved value to all elements in my hash?
by Porculus (Hermit) on Jul 10, 2008 at 20:15 UTC
    With all due respect to Kyle, I don't believe it has anything at all to do with using "1".

    I think you're still misunderstanding what kyle said.

    Indeed, the problem isn't that you were using "1" specifically -- but kyle didn't say that. He said that the problem is that you were using a value that wasn't a hashref and then later trying to treat it as one (and the value you were using that wasn't a hashref happened to be "1").

    When I extend it to two dimensions, it becomes a hash of hashes and the first dimension's keys must become references to the second dimenion hashes. So now keys %booklist_1 is a bunch of hash references, and no longer the bunch of book_ids I set them to originally.

    No. The keys don't change. I believe the keys can never be anything other than strings. It's the values that become hash references in a hash of hashes.

    I commend Data::Dumper to you -- it really is a good way of visualising what's going on underneath your data structures. And good luck -- I think even the most wizened master here will agree that the easiest thing to do with Perl data structures is to mess them up. :)

Re^2: Why is my code assigning the last-retrieved value to all elements in my hash?
by kyle (Abbot) on Jul 10, 2008 at 20:56 UTC

    With all due respect to Kyle, I don't believe it has anything at all to do with using "1".

    It's not "1" specifically that's the problem. The problem is using any particular static string for every book ID. You had the same problem using "ok" instead of "1". You'd have the same problem using "this_will_work_for_sure" or a million other things. It's also a problem you wouldn't have if you'd use strict because it won't allow you to use a string as a reference.

Re^2: Why is my code assigning the last-retrieved value to all elements in my hash?
by polettix (Vicar) on Jul 11, 2008 at 08:45 UTC
    Really the central problem was extending a one-dimensional hash to a two-dimensional one and then expecting the first-dimension's keys to remain scalars. Having extended the original hash into a hash of hashes, clearly the first-dimension's keys had to become hash-refs.

    ...

    When I extend it to two dimensions, it becomes a hash of hashes and the first dimension's keys must become references to the second dimenion hashes. So now keys %booklist_1 is a bunch of hash references, and no longer the bunch of book_ids I set them to originally.

    (Emphasis was added by me.)

    Just a nit-pick that may prove useful in the future: hashes are made of key/value pairs, in which the key is something closer to a string than to a scalar, and the value is a scalar. In particular, the value can be a reference to a hash.

    Thus, there's no way to put a reference in the key value of a regular* Perl hash. The most you can have is that the "stringification" of a reference can be used as a hash key, but this is something different: you can't use the hash key to directly* access the reference any more using some obscure dark magic.

    * I'm using the words regular and directly because I'm sure that there will be someone pointing out that there are modules/ways to have a magical hash that has whatever key you want, and that you can access a reference even if all you have is a stringification! :D

    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Io ho capito... ma tu che hai detto?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-04-25 22:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found