Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Re^5: csv to hash table

by sundialsvc4 (Abbot)
on Nov 19, 2013 at 14:56 UTC ( #1063344=note: print w/ replies, xml ) Need Help??


in reply to Re^4: csv to hash table
in thread csv to hash table

We really need to see the output.   I see a potential problem here in that you are stashing “a reference to @array” ... while that is a single variable.   Hence, all of the references will be to the same block of storage, namely, @array.   In Fortran parlance, all of the references are EQUIVALENCEd.   They will all be seen to contain the last contents of @array, and a change to any one will be reflected in every other, because “you are actually looking at one block of storage, albeit through several mirrors.

I think that you need to be sure that each hash-bucket contains a uniquehashref, and that the values get pushed onto that.   Perl’s “auto-vivification” feature comes in handy, with something like this:

use strict; use warnings; use Data::Dumper; my @arry = ( "key", 1, 2, 3 ); my $hash; my $key = shift @arry; # NEXT STATEMENT 'AUTOMAGICALLY' CREATES A HASH-ENTRY FOR $key # AND CAUSES IT TO CONTAIN AN EMPTY ARRAY IF IT # DOES NOT ALREADY EXIST: push @{ $hash->{$key} }, $_ foreach @arry; print Data::Dumper->Dump([ \@arry, $hash], ["arry", "hash"] );
gives ...
$arry = [ 1, 2, 3 ]; $hash = { 'key' => [ 1, 2, 3 ] };

The foreach clause is shorthand for an equivalent loop.   $_ contains the value within each iteration.   Notice how this loop is non-destructive to the content of @arry, iterating through its values without disturbing them.   The magic works now, because we are making copies of each value and pushing those onto a new arrayref (created on-demand) within the hash-bucket for $key.   Each hash-bucket, and each of the values therein, is distinct.

In the statement-of-interest, @{ ... } is part but not all of the magic.   Here, we are telling Perl that the value within the hash-bucket should be interpreted as / initialized to an arrayref.   Perl will automatically create a hash-entry (of course) on demand, because that is what hashes do, but here we’re declaring its type and immediately using it.   We can “auto-vivify” hashrefs, too, so that a line of code something like this ... actually Just Works™:

$hash->{"hickory"}{"dickory"}{"dock"} = "clock";
gives...
$hash = { 'hickory' => { 'dickory' => { 'dock' => 'clock' } } };


Comment on Re^5: csv to hash table
Select or Download Code
Re^6: csv to hash table
by choroba (Canon) on Nov 19, 2013 at 15:42 UTC
    while that is a single variable
    Not really, as the variable @array is declared with my inside the loop.
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re^6: csv to hash table
by waytoperl (Beadle) on Nov 19, 2013 at 18:40 UTC

    Thanks for input. Basically hash will group keys with duplicate values. I replaced with new code by commenting-out warn message with duplicate keys. While in execution, there is error "Global symbol "$hash" requires explicit package name at ./file_name.pl line 69." I don't have hash_ref to hash, to my understanding, without defining hash_ref we can't refer to/and have data written in hash table. Please correct.

    sub mainCSV { # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open +$infile_CSV: $!\n"; my %hash = (); my $hash_ref = \%hash; while (my $line = <$infile_CSV1>) { chomp; $line =~ s/\s*\z//; my @array_CSV = split /,/, $line; my $key_CSV = shift @array_CSV; push @{ $hash->{$key_CSV} }, $_ foreach @array_CSV; ++++ Error + ++++ print Data::Dumper->Dump([ \@array_CSV, $hash], ["array_CSV", +"hash"] ); ++++ Error +++++ #if ($hash{$key_CSV}) #{ # warn "Duplicate key '$key_CSV'"; #}; #$hash{$key_CSV} = \@array_CSV; } # Explicit scalar context my $size = scalar keys %hash; # Open the output file and save hash in $outfile_RX_CSV #open (my $outfile2, '>', "$outfile_CSV") or die "Unable to open $ +outfile_CSV: $!\n"; #print $outfile2 Dumper(\%hash); #close $outfile2; #print "Stored $size list of pins in $outfile_CSV file.\n"; # Return a reference to the hash. #return %hash; }

      The syntax for accessing values in a hash via a hash variable is different from the syntax for access values in a hash via a reference to a hash variable. You are using the one where you should be using the other, thus you are getting an error.

      To access a value in a hash via a hash variable, you can use the following syntax:

      my $value = $hash{$key};

      To access a value in a hash via a reference to a hash variable, you can use the following syntax:

      my $value = $hash_ref->{$key};

      The -> in this second example dereferences the hash ref.

      You have a hash variable (%hash) and a reference to a hash variable ($hash_ref). You don't need the latter, but you can use it if you want to. In fact, you declare $hash_ref and set it to a reference to %hash, but you don't use it anywhere, so you can simply remove it. It makes no difference in the code you posted.

      The first line you marked with "++++ Error ++++" includes: $hash->{$key_CSV}. Because $hash is followed by ->, $hash must be a scalar containing a reference, but you don't have such a variable defined in the code you have posted.

      If you change that bit to $hash{$key_CSV}, then you will be accessing the value from %hash which you have declared and initialized.

      At the second line marked with "++++ Error ++++", you have $hash. This is a scalar variable but in the code you posted it is not declared or initialized. While $hash{$key} accesses a value in the hash %hash, $hash does not refer to %hash at all, it refers to the scalar with a similar name.

      The ability to use the same "name" to refer to different variables can be a confusing aspect of Perl. Remember that $name, @name and %name are three different variables: changes to one do not affect the others. It can be more confusing that $name{$key} accesses %name rather than $name, but that's the way it is.

      There are many ways you could change the subroutine you posted to eliminate the errors. Here are a couple of simple changes for you to consider:

      sub mainCSV { # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open $infile_CSV: $!\n"; my %hash = (); while (my $line = <$infile_CSV1>) { chomp; $line =~ s/\s*\z//; my @array_CSV = split /,/, $line; my $key_CSV = shift @array_CSV; push @{ $hash{$key_CSV} }, $_ foreach @array_CSV; print Data::Dumper->Dump([ \@array_CSV, \%hash], ["array_CSV", + "hash"] ); } # Explicit scalar context my $size = scalar keys %hash; }

      Or

      sub mainCSV { # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open $infile_CSV: $!\n"; my %hash = (); my $hash_ref = \%hash; while (my $line = <$infile_CSV1>) { chomp; $line =~ s/\s*\z//; my @array_CSV = split /,/, $line; my $key_CSV = shift @array_CSV; push @{ $hash_ref->{$key_CSV} }, $_ foreach @array_CSV; print Data::Dumper->Dump([ \@array_CSV, $hash_ref], ["array_CS +V", "hash_ref"] ); } # Explicit scalar context my $size = scalar keys %hash; }

      And if you really want to do it the second way, you can simplify that to:

      sub mainCSV { # Open the CSV input file open (my $infile_CSV1, '<', "$infile_CSV") or die "Unable to open $infile_CSV: $!\n"; my $hash_ref = {}; while (my $line = <$infile_CSV1>) { chomp; $line =~ s/\s*\z//; my @array_CSV = split /,/, $line; my $key_CSV = shift @array_CSV; push @{ $hash_ref->{$key_CSV} }, $_ foreach @array_CSV; print Data::Dumper->Dump([ \@array_CSV, $hash_ref], ["array_CS +V", "hash_ref"] ); } # Explicit scalar context my $size = scalar keys %$hash_ref; }

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (7)
As of 2015-07-05 21:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (68 votes), past polls