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

Loading an anonymous hash

by pglenski (Beadle)
on Mar 19, 2008 at 14:36 UTC ( [id://675005]=perlquestion: print w/replies, xml ) Need Help??

pglenski has asked for the wisdom of the Perl Monks concerning the following question:

From my Cobol days I tried to minic the record layout using an anonymous hash. Here's what I have:
$Employee_Rec = [ {Emp_No=>1, Emp_Lname=>2, Emp_Fname=>3, Emp_SSN=>4, Emp_DOB=>5, Emp_aka=>6} ];
I would like to read a file (comma delimited), load the hash, and process, etc. What's the necessary code?
open(IN,"input.txt") or die("Can't open input.txt"); while(<IN>) { chomp; magic code here ... ??? print "$Employee_Rec->{Emp_No} \n"; print "$Employee_Rec->{Emp_Lname} \n"; print "$Employee_Rec->{Emp_Fname} \n"; print "$Employee_Rec->{Emp_SSN} \n"; print "$Employee_Rec->{Emp_DOB} \n"; print "$Employee_Rec->{Emp_aka} \n"; } close(IN);

Replies are listed 'Best First'.
Re: Loading an anonymous hash
by ikegami (Patriarch) on Mar 19, 2008 at 14:46 UTC

    [ { is a reference to an (anonymous) array of references to (anonymous) hashes. However, in the second snippet, you use it as a reference to a hash.

    Anyway, the missing magic is Text::CSV and a hash slice.

    use strict; use warnings; use Text::CSV qw( ); my $csv = Text::CSV->new(); open(my $fh_in, '<', 'input.txt') or die("Can't open input.txt: $!\n"); while (<$fh_in>) { $csv->parse($_) or die("Incorrectly formatted line ($.)\n"); my %Employee_Rec; @Employee_Rec{qw( Emp_No Emp_Lname Emp_Fname Emp_SSN Emp_DOB Emp_aka )} = $csv->fields(); print "$Employee_Rec{Emp_No} \n"; print "$Employee_Rec{Emp_Lname} \n"; print "$Employee_Rec{Emp_Fname} \n"; print "$Employee_Rec{Emp_SSN} \n"; print "$Employee_Rec{Emp_DOB} \n"; print "$Employee_Rec{Emp_aka} \n"; }

    Update: If you really did want to use field indexes,

    use strict; use warnings; use Text::CSV qw( ); my $csv = Text::CSV->new(); my %Employee_Field_Idx_Lkup = ( Emp_No => 0, Emp_Lname => 1, Emp_Fname => 2, Emp_SSN => 3, Emp_DOB => 4, Emp_aka => 5, ); open(my $fh_in, '<', 'input.txt') or die("Can't open input.txt: $!\n"); while (<$fh_in>) { $csv->parse($_) or die("Incorrectly formatted line ($.)\n"); my @fields = = $csv->fields(); my %Employee_Rec; @Employee_Rec{keys %Employee_Field_Idx_Lkup} = @fields[values %Employee_Field_Idx_Lkup]; print "$Employee_Rec{Emp_No} \n"; print "$Employee_Rec{Emp_Lname} \n"; print "$Employee_Rec{Emp_Fname} \n"; print "$Employee_Rec{Emp_SSN} \n"; print "$Employee_Rec{Emp_DOB} \n"; print "$Employee_Rec{Emp_aka} \n"; }
Re: Loading an anonymous hash
by samtregar (Abbot) on Mar 19, 2008 at 14:44 UTC
    I don't know COBOL, but this doesn't make a lot of sense to me:

    $Employee_Rec = [ {Emp_No=>1, Emp_Lname=>2, Emp_Fname=>3, Emp_SSN=>4, Emp_DOB=>5, Emp_aka=>6} ];

    That's an anonymous array with a single element, an anonynmous hash where the values are sequential integers. What were you trying to accomplish by creating this structure? Are you by any chance trying to use the deprecated psuedo-hash system?

    Later in the code it looks like you're treating $Employee_Rec as a simple hash-ref, which makes more sense. If that's what you want you don't need to do any pre-initialization and the "magic code" you're looking for is probably something like:

    my @data = split(',',$_); $Employee_Rec->{Emp_No} = $data[0]; $Employee_Rec->{Emp_Lname} = $data[1]; ...

    That will only work for very simple CSV files though - if you're dealing with something more complicated take a look at Text::CSV_XS.

    -sam

Re: Loading an anonymous hash
by apl (Monsignor) on Mar 19, 2008 at 15:24 UTC
    As a one-time PL/1 programmer (we got our record layouts from you COBOL guys), I'd eschew the record structure you want to use. ikegami gave you a great solution; I'd suggest tweaking
    my %Employee_Rec; @Employee_Rec{qw( Emp_No Emp_Lname Emp_Fname Emp_SSN Emp_DOB Emp_aka )} = $csv->fields(); print "$Employee_Rec{Emp_No} \n"; print "$Employee_Rec{Emp_Lname} \n"; print "$Employee_Rec{Emp_Fname} \n"; print "$Employee_Rec{Emp_SSN} \n"; print "$Employee_Rec{Emp_DOB} \n"; print "$Employee_Rec{Emp_aka} \n";

    to

    my ( $Emp_No, $Emp_Lname, $Emp_Fname, $Emp_SSN, $Emp_DOB, $Emp_aka +) = $csv->fields(); print "$Emp_No \n"; print "$Emp_Lname \n"; print "$Emp_Fname \n"; print "$Emp_SSN \n"; print "$Emp_DOB \n"; print "$Emp_aka \n";

    You gain nothing from storing the information in a hash (unless you were going to make a Hash of Hashes, keyed on the Employee Number). Prefacing the fields with Emp_ indicates the fields are related.

Re: Loading an anonymous hash
by moritz (Cardinal) on Mar 19, 2008 at 14:45 UTC
    The [ ... ] are causing your problem. They create an anonymous array in which your anonymous hash is.

    Try it without them:

    $Employee_Rec = { Emp_No =>1, Emp_Lname =>2, Emp_Fname =>3, Emp_SSN =>4, Emp_DOB =>5, Emp_aka =>6, };
Re: Loading an anonymous hash
by friedo (Prior) on Mar 19, 2008 at 14:47 UTC

    What you've got there is an array reference with a hash reference as its only element. To make an anonymous hash reference, you just use curlies ({}). Since you want to read in multiple comma-delimited rows, you probably want an array of hash references, one hashref for each row.

    my @records; # store the hashrefs in here my @keys = qw(Emp_No Emp_Lname Emp_Fname Emp_SSN Emp_DOB Emp_aka); open(IN,"input.txt") or die("Can't open input.txt"); while(<IN>) { chomp; my %Employee_Rec; @Employee_Rec{@keys} = split /,/, $_; # hash slice print "$Employee_Rec{Emp_No} \n"; print "$Employee_Rec{Emp_Lname} \n"; print "$Employee_Rec{Emp_Fname} \n"; print "$Employee_Rec{Emp_SSN} \n"; print "$Employee_Rec{Emp_DOB} \n"; print "$Employee_Rec{Emp_aka} \n"; push @records, \%Employee_Rec; } close(IN);

    To inspect @records and make sure you've built it correctly, you can use Data::Dumper.

      Nicely done. I remember trying to do something like this a while back and struggling for a long time because my hash was not properly localised. You have to make sure that my %Employee_Rec is my'd inside that while loop otherwise it will no longer be anonymous and all you'll get is an array full of references to the same hash---the last one you entered...

      ........
      Those are my principles. If you don't like them I have others.
      -- Groucho Marx
      .......

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-20 02:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found