CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
returning a hash from a subroutine...

 



ccin1492
Novice

Apr 8, 2009, 3:28 PM

Post #1 of 10 (614 views)
returning a hash from a subroutine... Can't Post

I have a subroutine that I use to read from multiple files and gather some data that I put in a hash. My hash in the subroutine looks like this:


Code
sub parse_file { 
my %caps = {}
while (<FILE>) { $caps->{$net} = val ; }
return $caps ;
}


Obviously, this is over simplified...

I loop over the files and call the subroutine like this:


Code
my $i = 0 ; 
foreach $file (@inputs) {
open (FILE, "$file") ;

%{$CAPS[$i]} = parse_file() ;
$i++

close (FILE);
}


The problem I am having is the data in $CAPS[0] end up being the same as $CAPS[1]. Somehow I lost the data from the first file. I think what is happening is that I'm placing a reference into $CAPS[0] to %caps and not a copy. So my question is how do I copy %caps to $caps[$i]?

I hope this is clear...


KevinR
Veteran


Apr 8, 2009, 8:13 PM

Post #2 of 10 (606 views)
Re: [ccin1492] returning a hash from a subroutine... [In reply to] Can't Post

You need to post some of your real code because what you have posted is not enough or it makes no sense or is just plain wrong.
-------------------------------------------------


ccin1492
Novice

Apr 8, 2009, 9:41 PM

Post #3 of 10 (603 views)
Re: [KevinR] returning a hash from a subroutine... [In reply to] Can't Post

The code I provided is pretty much the core of the script, so providing more of my code won't do you much good, or might confuse you even more, if that's possible. And you're probably right in that it's all wrong. That's why I'm asking for help.

Here's what I'm trying to do. I have to files with data I want to correlate. The files have a list of signals and their capacitance. Both files have the same list of signals but the capacitance are different and I want to find out by how much.

So I'm reading the files and putting the information in a hash with the signal as the key and the cap as the value, but I have to do this for both files. I can create two separate hash tables which is what I have now, but it doesn't scale. What I mean is I might want to compare two files, or five. That's where I need help; I don't know what data structure to use that would be the most efficient.

Thanks!


KevinR
Veteran


Apr 9, 2009, 9:18 AM

Post #4 of 10 (593 views)
Re: [ccin1492] returning a hash from a subroutine... [In reply to] Can't Post

If the signals are unique you can use them as the hash keys, and probably the capacitance of each signal/key for all the files could be stored in an array that is the value of each signal/key.

Something like this:


Code
my @inputs = (a list of files); 
my %signals;
foreach my $file (@inputs) {
open (my $IN, "<", $file) or warn "Can't open file $file: $!";
while(<$IN>){
chomp;
# parse data here into $key (signal) and $val (capacitance)
push @{$signals{$key}},$val;
}
close($IN);
}


You could write a seperate subroutine to just parse the data and return the data back to the calling subroutine but that seems like a bit of overkill and added confusion for you at this point in time.
-------------------------------------------------


(This post was edited by KevinR on Apr 9, 2009, 9:29 AM)


ccin1492
Novice

Apr 9, 2009, 11:51 AM

Post #5 of 10 (587 views)
Re: [KevinR] returning a hash from a subroutine... [In reply to] Can't Post

First, thanks for your help.

Looking at the code, where is the relation between the file and the cap value? In addition to knowing the cap value of the signal, I need to know what file the cap value came from. Is that clear? Ok, so the lookup table needs to look like this:


Code
   FILE  | A   | B   | C   | 
---------|-----|-----|-----|
signal a | val | val | val |
signal b | val | val | val |
signal c | val | val | val |
etc.


I think you're right. I need to show you my code... I'll provide that in the next post.


ccin1492
Novice

Apr 9, 2009, 12:32 PM

Post #6 of 10 (585 views)
Re: [KevinR] returning a hash from a subroutine... [In reply to] Can't Post

Ok, here's the real code...


Code
my @CAP_VAL = () ; 

my $num = 0 ;
foreach my $file (@input) {
print "RC File $num: $file\n" ;
if ($file =~ /\.gz/) {
open (FILE, "gunzip -c $file |") || die "can't open file $file !!\n" ;
} elsif ($file =~ /\.bz2/) {
open (FILE, "bunzip2 -c $file |") || die "can't open file $file !!\n" ;
} else {
open (FILE, "$file") || die "can't open file $file !!\n" ;
}

$CAP_VAL[$num] = parse_spef_file() if ($file =~ /\.spef/) ;
$num++ ;

close FILE ;
}

# test values in hash...
print "$CAP_VAL[0]->{fft_256_c_2_r_n207}\n" ;
print "$CAP_VAL[1]->{fft_256_c_2_r_n207}\n" ;

sub parse_spef_file {

my %cap = {} ;
my %f1map = {} ;

my $nmap = 0 ;
my $end = 0 ;
my $total_net = 0 ;

my $net = "" ;

while (my $line = <FILE>) {
if($line =~ /\*NAME_MAP/) {
$nmap = 1 ;
next ;
}
if($line =~ /\*PORTS/) {
$nmap = 0 ;
next ;
}
if($nmap == 1) {
chop $line ;
next if($line =~ /^\s+$/) ;
my ($key, $value) = split /\s+/, $line ;
$value =~ s/\\//g ;
$f1map{$key} = $value ;
}
if($line =~ /\*D_NET/) {
my ($front, $key, $end) = split /\s+/, $line ;
$net = $f1map{$key};
if($res) {
$cap{$net}= proc_sum_resistance() ;
} else {
if ($end =~ /\d+[fF]/) {
$end =~ s/[fF]//g ;
$cap->{$net} = $end*1e-3 ; #convert fF to pF
} elsif ($end=~ /\de-(\d+)/) {
my $expvalue = eval(10 **(- $1)) ;
$end =~ s/e-\d+// ;
$cap->{$net} = $end * $expvalue * (1e-3) ; #convert SCI to pF
} elsif ($end =~ /\d+[pF]/) {
$end =~ s/[pF]//g ; #cap value in pF
$cap->{$net} = $end ; # no need to convert
} else {
$end =~ s/[pPfF]//g ; #if units of pF or no units
$cap->{$net} = $end*1e-3 ; #cap value in pF
}
}
$total_net++ ;
}
}

print "Total Nets: $total_net\n" ;

return $cap ;
}



KevinR
Veteran


Apr 9, 2009, 1:58 PM

Post #7 of 10 (583 views)
Re: [ccin1492] returning a hash from a subroutine... [In reply to] Can't Post

post some lines of data the code parses so I can run some tests when I get a chance.
-------------------------------------------------


KevinR
Veteran


Apr 9, 2009, 3:02 PM

Post #8 of 10 (580 views)
Re: [ccin1492] returning a hash from a subroutine... [In reply to] Can't Post

I'm not sure if you are mixed up about something, you declare a hash in the function:


Code
my %cap = {};


and then later you have:


Code
$cap{$net}= proc_sum_resistance() ;


Which is OK, but later still you are storing values in a reference to a hash ($cap):


Code
$cap->{$net} = $end*1e-3 ; #convert fF to pF


$cap->{...} and $cap{...} are two seperate data structures entirely. $cap{...} stores data in %cap but $cap->{...} does not. Are you running your code with "strict" enabled?
-------------------------------------------------


ccin1492
Novice

Apr 9, 2009, 5:43 PM

Post #9 of 10 (572 views)
Re: [KevinR] returning a hash from a subroutine... [In reply to] Can't Post

Actually, I am running with "strict", but it didn't complain.

So I finally got it to work. Here's what I did:

1, changed $cap->{...} to $cap{...},

Like you said they are two different data structures, but I don't quite understand the subtleties.

2, changed "return $cap" to "return %cap", and

I'm don't know what the first one returns, but I'm sure the second returns a hash.

3, changed $CAP_VAL[$num] t0 %{ $CAP_VAL[$num] }.

This was the key. I'm not sure why, but the %{ } around the array made sure I captured the complete array.

Thanks for your help and time!


KevinR
Veteran


Apr 9, 2009, 5:55 PM

Post #10 of 10 (570 views)
Re: [ccin1492] returning a hash from a subroutine... [In reply to] Can't Post

Actually, I am running with "strict", but it didn't complain.

Then you must have declared $cap somewhere otherwise perl would have exited with an error.

So I finally got it to work. Here's what I did:

1, changed $cap->{...} to $cap{...},

Like you said they are two different data structures, but I don't quite understand the subtleties.

One is a hash and one is a reference to a hash, but not the same hash

2, changed "return $cap" to "return %cap", and

I'm don't know what the first one returns, but I'm sure the second returns a hash.

The first one returns the reference $cap, the second one does return the hash %cap but as a flattened list, that can be very important to understand.

3, changed $CAP_VAL[$num] t0 %{ $CAP_VAL[$num] }.

This was the key. I'm not sure why, but the %{ } around the array made sure I captured the complete array.

Without seeing more context that isn't helpful for me to know why that makes your code work. %{} is dereferencing $CAP_VAL[$num] into its hash form, but that needs to be assigned to something or used to loop over the hash, for example, this would make sense if $CAP_VAL[$num] is a reference to a hash:

my %hash = %{$CAP_VAL[$num]};


Thanks for your help and time!

You're welcome
-------------------------------------------------

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives