Mailing List

Flat
perl question (with question following this time)
User: lorik
Date: 3/31/2010 10:21 am
Views: 701
Rating: 0

Hello, I work on campus and am having a problem with hash keys being overwritten as new data is added to the hash, the values are not overwritten. I suspect it is a straightforward problem with loop control, but I am a beginner and my code is messy, so I do not think it would be productive to post the code itself here.

Is there someone who would be willing to meet next week to help me solve this?  If so please respond and let me know when, and what you will charge.

Cheers, Lori

Re: perl question (with question following this time)
User: jt
Date: 3/31/2010 10:24 am
Views: 0
Rating: 0
You should just post your code to the mailing list, and one of us will get you an answer quickly.
Re: perl question (with question following this time)
User: lorik
Date: 3/31/2010 10:59 am
Views: 0
Rating: 0

I really don't think this will help, because it's at the end of a long subroutine, but as it has been suggested I will try.

%halfSibFamily is a hash of arrays. It is built in a foreach loop, and the structure prints correctly. When I try to make a hash of a hash of arrays with this statement:

$gen2{$MP} = %halfSibFamily;

an element? gets added with the correct key & value, however the VALUES (hashes of arrays) of all previous elements are overwritten as the new value.  The keys do not change (remain correct)

So in the end I have a hash of hash of arrays with the expected number of elements, and all the correct keys for the outer hash, but all the the inner hashes are the same (the last one to be generated)

 

Re: perl question (with question following this time)
User: jt
Date: 3/31/2010 11:17 am
Views: 180
Rating: 0

I really don't think this will help, because it's at the end of a long subroutine, but as it has been suggested I will try.

What you just said is probably the first problem. If you can't fit the entire subroutine on your screen at once using a 12pt font, then it's probably too long and should be broken into separate easily testable/debuggable subroutines.

%halfSibFamily is a hash of arrays. It is built in a foreach loop, and the structure prints correctly. When I try to make a hash of a hash of arrays with this statement:

$gen2{$MP} = %halfSibFamily

This should probably be written as:
$gen2{$MP} = \%halfSibFamily;
Each element in a hash can only contain a reference to a hash.  However, you may have just mistakenly typed that when you posted here.

an element? gets added with the correct key & value, however the VALUES (hashes of arrays) of all previous elements are overwritten as the new value.  The keys do not change (remain correct)

So in the end I have a hash of hash of arrays with the expected number of elements, and all the correct keys for the outer hash, but all the the inner hashes are the same (the last one to be generated

I think what's going wrong for you is that you're using the same hash reference over and over. That would explain the results you're getting. Here's an example of what I mean:
my %exes;
my %whys;
foreach my $x ('a'..'c') {
        foreach my $y (1..3) {
                $whys{$y} = $x;
        }
        $exes{$x} = \%whys;
}
With that code you would probably expect to get a hash that looks something like:
{
a => { 1 => 'a', 2 => 'a', 3 => 'a' },
b => { 1 => 'b', 2 => 'b', 3 => 'b' },
c => { 1 => 'c', 2 => 'c', 3 => 'c' },
}
However what you're really getting is 
{
a => { 1 => 'c', 2 => 'c', 3 => 'c' },
b => { 1 => 'c', 2 => 'c', 3 => 'c' },
c => { 1 => 'c', 2 => 'c', 3 => 'c' },
}
That's because you're reusing the hash and therefore all your hash references point to the same spot in memory. You need a new hash on each loop like this:
my %exes;
foreach my $x ('a'..'c') {
        my %whys;
        foreach my $y (1..3) {
                $whys{$y} = $x;
        }
        $exes{$x} = \%whys;
}
Does that make sense to you?

JT Smith
ph: 703-286-2525 x810
Create like a god, command like a king, work like a slave.

EDIT: Fixed a few typos:

Re: perl question (with question following this time)
User: mcholste
Date: 3/31/2010 11:23 am
Views: 0
Rating: 0
JT is right on both counts.  There is one other thing I'll mention for completeness: you could get away with the outer-scoped hash if you assign copies of the data instead of references, like this:

my %exes;
my %whys;
foreach my $x ('a'..'c') {
        foreach my $y (1..3) {
                $whys{$y} = $x;
        }
        $exes{$x} = { %whys }; # the curly braces return a reference to a new hash which is a point-in-time copy of the original
}

You would then access it like $exes{'a'}->{1}.

On Wed, Mar 31, 2010 at 10:17 AM, <jt@plainblack.com> wrote:

jt wrote:

I really don't think this will help, because it's at the end of a long subroutine, but as it has been suggested I will try.

What you just said is probably the first problem. If you can't fit the entire subroutine on your screen at once using a 12pt font, then it's probably too long and should be broken into separate easily testable/debuggable subroutines.

%halfSibFamily is a hash of arrays. It is built in a foreach loop, and the structure prints correctly. When I try to make a hash of a hash of arrays with this statement:

$gen2{$MP} = %halfSibFamily




This should probably be written as:

$gen2{$MP} = \%halfSibFamily;

Each element in a hash can only contain a reference to a hash.  However, you may have just mistakenly typed that when you posted here.

an element? gets added with the correct key & value, however the VALUES (hashes of arrays) of all previous elements are overwritten as the new value.  The keys do not change (remain correct)

So in the end I have a hash of hash of arrays with the expected number of elements, and all the correct keys for the outer hash, but all the the inner hashes are the same (the last one to be generated


I think what's going wrong for you is that you're using the same hash reference over and over. That would explain the results you're getting. Here's an example of what I mean:

my %exes;
my %whys;
foreach my $x ('a'..'c') {
        foreach my $y (1..3) {
                $whys{$y} = $x;
        }
        $exes{$x} = \%whys;
}


With that code you would probably expect to get a hash that looks something like:

{
a => { 1 => 'a', 2 => 'a', 3 => 'a' },
b => { 1 => 'b', 2 => 'b', 3 => 'b' },
c => { 1 => 'c', 2 => 'c', 3 => 'c' },
}

However what you're really getting is 

{
a => { 1 => 'c', 2 => 'c', 3 => 'c' },
b => { 1 => 'c', 2 => 'c', 3 => 'c' },
c => { 1 => 'c', 2 => 'c', 3 => 'c' },
}

That's because you're reusing the hash and therefore all your hash reference point to the same spot in memory. You need a new has on each loop like this:

my %exes;
foreach my $x ('a'..'c') {
        my %whys;
        foreach my $y (1..10) {
                $whys{$y} = $x;
        }
        $exes{$x} = \%whys;
}


Does that make sense to you?


JT Smith
ph: 703-286-2525 x810

Create like a god, command like a king, work like a slave.

View Online




Madison Area Perl Mongers - MadMongers
http://www.madmongers.org


Re: perl question (with question following this time)
User: lorik
Date: 3/31/2010 12:00 pm
Views: 0
Rating: 0

Thank you for looking at that.

The idea that I am reusing the same hash makes sense, but how to fix it does not.

Your example is similar to those online, in my manual etc, but I do not understand how to translate that to my situation, which is why I was hoping to hire someone to take a look at my code.

 

 

Re: perl question (with question following this time)
User: jt
Date: 3/31/2010 12:22 pm
Views: 0
Rating: 0
I'd say first thing is first. Modify your code to boil the subroutine in question down to it's basics (if you can do that).

Then post the subroutine here and we can look at it for you. Or just attach the whole program as an attachment here. You may or may not get someone to look at it, but you'd get it quickly.

Perhaps someone will pop up willing to work for cash, I just don't know.

Finally, we're having a meeting on April 20th at Altn Bach's Town Tap. If you haven't gotten someone to fix it by then, bring it with you to our meeting and we'll be happy to help you out.
Re: perl question (with question following this time)
User: lorik
Date: 3/31/2010 3:18 pm
Views: 5
Rating: 0

Hello,

Are you saying I need to alter the generation of the first hashes in the foreach loop?

$halfSibFamily{$indId}=[@individualGen2];

rather than the statement that puts all of these hashes as they come out of the loop in another hash?

$sizeOfGen2 = keys %gen2;

Since this hasn't worked as a way to hire someone so far, I've attached the subroutine. Is there somewhere else in Madison or on the UW campus that I can try to hire some help?

Cheers.

Re: perl question (with question following this time)
User: jt
Date: 3/31/2010 3:50 pm
Views: 0
Rating: 0

You're almost certainly having problems because your code isn't scoped at all. All your variables are global. What I mean by that is that your variables look like:

@halfSibId;

When they should look like:

my @halfSibId;

In addition, it appears that you're including a few other scripts into this one using the 'require' command. And that the functions that those programs are bringing are also possibly manipulating your variables. The reason I say that is because you have all sorts of variables in your code that you're only using once (therefore they are likely worthless unless something else is manipulating them).

@halfSibId, $noCrosses, $noIndividuals, $noIndividualsPerCross

I'm not sure how to fix your code without rewriting it. It's going to be nearly impossible to debug because of the reliance on global variables everywhere.

As for finding someone to hire locally, this is the best place to do that. Keep in mind that most of the people on this list already have day jobs however, and may not have time to help you. If you just want someone to make it work, and you don't care if they are local, then check out http://jobs.perl.org. 

PreviousNext
Madison Area Perl Mongers