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

Hey guys, thanks again for all of the help. I believe I have figured out a lot of the silly errors I was making, and have a more general question. I am using a hash for the same data file as I showed before:
777666555 Smith Tom RM So 111222333 Jones Mary SD Fr 555444333 Johnson Lee IE Sr
I am reading it in from the file, and using split, am extracting the first piece of data (the ID) to be the hash key, and the remainder to be the values. Here is the snippet:
while(my $line2 = <INPUT>){ chomp($line2); my @splitStudent = split(' ', $line2); $size = @splitStudent; my $keys = splitStudent[0]; my $Lname = splitStudent[1]; my $Fname = splitStudent[2]; my $Major = splitStudent[3]; my $Year = splitStudent[4]; } my @IDSorted = sort(keys(%student));
However, I do not understand how to store the data from the entire file. It seems to me that this code would work only to read in one line. My problem arose when later, I am taking user input to determine if it matches a key...then, if so, outputting each piece of data corresponding to that key. How exactly would I obtain the Fname, Lname, and so on...in order to print?

Replies are listed 'Best First'.
Re: Hashes with multiple values?
by amarquis (Curate) on Mar 31, 2008 at 02:42 UTC

    There are several things that will keep your code from compiling, but I take it you want big picture comments/criticism so here goes:

    my($key,$value) = split /[\d]{9}\s+[a-z|A-Z]{1,9}\s+[a-z|A-Z]{1,9}

    This looks like you are mixing two concepts, splitting a string and match/capture on a string. Split's first argument is a pattern that matches what separates the things you want in the string, and it returns those things. You might want this:

    my($key, @values) = split / /, $this_line

    That'll put the '777666555' field into $key, and stuff all the other fields into the array. As far as getting that array into a hash (making the hash have multiple values), I'd check out perldoc perldsc. It is a good tutorial for Perl's compound data structures.

    But, like I said, there are some wonky things with your example code that I'd clean up before doing anything else. (Another sort of mixed concept thing going on is that you try to dump INPUT into an array the line before you open it, and then later try to iterate over INPUT anyway.) You can fix several problems (like the missing greater than on while(<INPUT>) just by trying to run the above, Perl will choke, die, and give you pretty verbose error messages.

Re: Hashes with multiple values?
by jwkrahn (Abbot) on Mar 31, 2008 at 03:39 UTC
    #!/usr/bin/perl
    use strict;

    And don't forget:

    use warnings;

    my $value;

    You don't need this variable in file scope

    my $infile = "student.data";
    my @lines = <INPUT>;

    You haven't opened the INPUT filehandle yet so that statement makes no sense.

    if(!open(INPUT, "<$infile")){
       print "Can't open file $infile\n";
       die;

    You should include the $! variable in your error statement so you know why it failed.   Why not just let die print out the error message?

    }
    while(<INPUT){

    You are missing the closing  > delimiter.

       chomp;
       my %hash = ();

    Because %hash is declared as a lexical variable inside the while loop it is only visible inside the while loop.

       my($key, $value) = split /[\d]{9}\s+[a-z|A-Z]{1,9}\s+[a-z|A-Z]{1,9}\s+[A-Z]{2}\s+[A-Z]{2}/;
        push @{$config{$key}}, $value;
    }

    split removes whatever the pattern matches and returns a list of everything that didn't match so it looks like nothing will be returned.   Your character class [a-z|A-Z] includes the '|' character but it doesn't look like your data contains that character.   What you probably want is something like:

    while ( <INPUT> ) {
       my ( $key, @values ) = split ' ', $_, -1;
       push @{ $config{ $key } }, @values;
    }

    @studentList = @{$config{"studentList"}};

    It doesn't appear that your data has a "studentList" key, it looks like all the keys are nine digit numbers.

    @sortedList1 = sort(keys, %hash);

    You can't use %hash here because it is lexically scoped to the while loop.

      Please use code tags <c> code goes here </c> or <code> code goes here </code>

        I did use code tags.    But thanks for asking.    :-)

Re: Hashes with multiple values?
by McDarren (Abbot) on Mar 31, 2008 at 05:00 UTC
    Lets say that you want to take your data file, and create a hash keyed by student name - then a canonical way of doing this might be as follows:
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my $sdata = 'student.data'; my %students; open my $infile, '<', $sdata or die "Cannot open $sdata:$!\n"; while (my $line = <$infile>) { chomp($line); my ($id,$name,$f3,$f4) = $line =~ m/^(\d+)\s(.*)\s(..)\s(..)$/; $students{$name}{id} = $id; $students{$name}{f3} = $f3; $students{$name}{f4} = $f4; } close $infile; print Dumper(\%students);
    The pattern match in the above assumes that the 3rd and 4th fields (not sure what they are) are always just two characters long, and everything between the ID and the 3rd field is the student name. It gives the following output:
    $VAR1 = { 'Smith Tom' => { 'f3' => 'RM', 'id' => '777666555', 'f4' => 'So' }, 'Johnson Lee' => { 'f3' => 'IE', 'id' => '555444333', 'f4' => 'Sr' }, 'Jones Mary' => { 'f3' => 'SD', 'id' => '111222333', 'f4' => 'Fr' } };
    If you wanted to then print a list of students, sorted by say, ID, then you could do something like:
    for my $student (sort {$students{$a}{id} <=> $students{$b}{id}} keys % +students) { print "$student => $students{$student}{id}\n"; }
    Hope this helps,
    Darren :)
Re: Hashes with multiple values?
by Zen (Deacon) on Mar 31, 2008 at 14:30 UTC
    Going to throw my two cents in here. Forget about the code for a second.

    A lot of your code is wrong, as you know. But the process you're following looks like you aren't even testing it. Write a couple lines and then do some prints to see if it's doing what you expect. Also, before you try to do this project, please read on:
    A) Hash, Array, Scalar in Perl
    B) File I/O
    C) Split
    D) Pattern Matching

    The Camel book is for newcomers like you. Have fun.