in reply to Re^5: read hash table from a subroutine or retrieve previously stored hash table from a file
in thread read hash table from a subroutine or retrieve previously stored hash table from a file

Okay, finally got some time to look at this.

The full explanation is hidden behind the <readmore>tag.

  1. First Up: Your input data.
     
    • You told us generally what the data structure looked like.
    • You posted what the expected output was (excellent, thank you).
    • You posted what the actual output was (excellent, thank you).
    • I can't find the actual input data anywhere (so you leave us to guess or reverse engineer it; not exactly the best way to help us help you).

    So I fabricated the following test.csvfile so I could start someplace:

    C_WREN,Group1 CAL_CLK,Group1 RX_IBIAS_2_25U[4:0],Group3 REF_RATE[9:0],Group3 AVD0,Group4 SIDDQ,Group7

  2. Second up: Subroutine won't compile.

    • You only provided a subroutine, no main code.
    • I added the following in front of your subroutine:
      #!/usr/bin/perl use strict; use warnings; foreach my $infile_name (@ARGV) { &mainCSV($infile_name); } exit;
    • When I ran it, I got the following:
      C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash>testhash.pl test.csv Global symbol "$infile_CSV" requires explicit package name at C:\Steve +\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl line 16. Global symbol "$infile_CSV" requires explicit package name at C:\Steve +\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl line 16. Global symbol "$outfile_CSV" requires explicit package name at C:\Stev +e\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl line 40. Global symbol "$outfile_CSV" requires explicit package name at C:\Stev +e\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl line 40. Global symbol "$outfile_CSV" requires explicit package name at C:\Stev +e\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl line 43. Execution of C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash\testhash.pl + aborted due to compilation errors.

    So your problems are more basic than just a failure to understand hashes.

    Normally, Perlmonks is not a code writing service, but you seem to be making a genuine effort, plus I accidentally made you wait far longer than anticipated, so what the heck, let's just debug this thing.

    1. "$infile_CSV" requires explicit package name

      This tells us you haven't defined $infile_CSV. This could be in a section of your code that is missing, which means you defined it is a global variable, which is a bad idea. Or it could be that you weren't doing use strict;. More than bad, it is a potentially fatal bad idea.

      The way to fix this is to get your subroutine to accept this filename as a parameter. I changed the following section:

      sub mainCSV { # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open + $infile_CSV: $!\n";

      to this:

      sub mainCSV { my ($infile_CSV, @extraStuff) = @_; if (!defined $infile_CSV) { $infile_CSV = ''; } # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open + $infile_CSV: $!\n";

      The @extraStuffis, of course, superfluous, but it hints toward how you might retrieve more than one parameter in the called subroutine.
      Moving on:

    2. "$outfile_CSV" requires explicit package name

      Same problem; you haven't defined $outfile_CSV.

      I saw no code to identify the output filename. So I changed this:

      # Open the output file and save hash in $outfile_RX_CSV open (my $outfile2, '>', "$outfile_CSV") or die "Unable to open $ +outfile_CSV: $!\n";

      to this:

      # Open the output file and save hash in $outfile_RX_CSV my $outfile_CSV = &getOutputFilename($infile_CSV); open (my $outfile2, '>', "$outfile_CSV") or die "Unable to open $ +outfile_CSV: $!\n";

      and added this to the bottom of the program:

      sub getOutputFilename { my ($inputFilename, @extraStuff) = @_; if (!defined $inputFilename) { $inputFilename = ''; } my @inputElements = split /\./, $inputFilename; my $inputExtension = pop @inputElements; if (!@inputElements) { push @inputElements, $inputExtension; $inputExtension = 'csv'; } $inputElements[-1] .= '_RX'; my $outputFilename = join '.', (@inputElements, $inputExtension); return $outputFilename; }

      The @extraStuffcontinues to be superfluous.

  3. Third up: Errors in your subroutine.

    • The above changes were made.
    • Now when I run it, I get the following:
      C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash>perl testhash2.pl test.c +sv Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 1. Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 2. Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 3. Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 4. Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 5. Use of uninitialized value $_ in scalar chomp at testhash2.pl line 25, + <$infile_CSV1> line 6. Number of Pins: 6 Undefined subroutine &main::Dumper called at testhash2.pl line 45, <$i +nfile_CSV1> line 6.

    So let's look at these.

    1. Use of uninitialized value $_ in scalar chomp

      Interesting. You assign the input to a named scalar variable, but then you chomp the default $_ -- which you are not using.

      Easy to fix. Change this:

      while (my $line = <$infile_CSV1>) { chomp; $line =~ s/\s*\z//;

      to this:

      while (my $line = <$infile_CSV1>) { chomp $line; $line =~ s/\s*\z//;

    2. Undefined subroutine &main::Dumper

      Ah! You're using Data::Dumper -- good move. Let's include that in the main routine.

      Change this:

      #!/usr/bin/perl use strict; use warnings; foreach my $infile_name (@ARGV)

      to this:

      #!/usr/bin/perl use strict; use warnings; use Data::Dumper; foreach my $infile_name (@ARGV)

  4. Fourth up: Back to the beginning.

    • The above changes were made.
    • Now when I run it, I get the following:
      C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash>perl testhash2.pl test.c +sv Number of Pins: 6 Stored 6 list of pins in test_RX.csv file. AVD0 => ARRAY(0x4bde48) SIDDQ => ARRAY(0x4cacf8) C_WREN => ARRAY(0x4e8f18) CAL_CLK => ARRAY(0x4a8468) REF_RATE[9:0] => ARRAY(0x4bdd10) RX_IBIAS_2_25U[4:0] => ARRAY(0x4bdce0)

    So it looks like we finally have gotten back to where you started -- we can reproduce your problem.

    Do you see now why we ask you to post short, but fully functional, code? PerlMonks is peopled by a bunch of volunteers, with real lives, who are not here to do your work for you, but to help you figure out how to do the work yourself. Fixing basic stuff like this is really, really time consuming for the person who didn't write it.

    No worries; this is a labor of love. But please, in the future: Please make an effort to help us help you. :-)

    Okay, so let's analyze the problem. I told you the issue was this line:

    $hash{$key_CSV} = \@array_CSV;

    You are storing the reference to the array in the hash. Later, you wish to pull out the value. Note the distinction. If you want to pull out the value, then you should put the value in.

    So I changed the following:

    my $key_CSV = shift @array_CSV; if ($hash{$key_CSV}) { warn "Duplicate key '$key_CSV'"; }; $hash{$key_CSV} = \@array_CSV;

    to this:

    my ($key_CSV, $value_CSV, @extraStuff) = @array_CSV; if ($hash{$key_CSV}) { warn "Duplicate key '$key_CSV'"; }; $hash{$key_CSV} = $value_CSV;

    The @extraStuffcontinues to be superfluous.

  5. Finally: The solution.

    • The above changes were made.
    • Now when I run it, I get the following:
      C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash>perl testhash2.pl test.c +sv Number of Pins: 6 Stored 6 list of pins in test_RX.csv file. AVD0 => Group4 SIDDQ => Group7 C_WREN => Group1 CAL_CLK => Group1 REF_RATE[9:0] => Group3 RX_IBIAS_2_25U[4:0] => Group3

    That looks an awful lot like the output you said you expected.

Summary: Making the following changes:

chomp $line; $line =~ s/\s*\z//; my @array_CSV = split /,/, $line; my ($key_CSV, $value_CSV, @extraStuff) = @array_CSV; if ($hash{$key_CSV}) { warn "Duplicate key '$key_CSV'"; }; $hash{$key_CSV} = $value_CSV;

Produces:

C:\Steve\Dev\PerlMonks\P-2013-11-23@0553-Hash>perl testhash2.pl test.c +sv Number of Pins: 6 Stored 6 list of pins in test_RX.csv file. AVD0 => Group4 SIDDQ => Group7 C_WREN => Group1 CAL_CLK => Group1 REF_RATE[9:0] => Group3 RX_IBIAS_2_25U[4:0] => Group3

Note: The @extraStuffis superfluous, left in for example purposes.

So, unless I'm missing something, it looks like all you had to do was store the value instead of the array reference.

Holler if this isn't what you were looking for.

  • Comment on Re^6: read hash table from a subroutine or retrieve previously stored hash table from a file
  • Select or Download Code