Question on perl function

Posted on 2003-10-31
Last Modified: 2010-03-04
Hello, I'm tyring to use perl to reference to a hash and then return the contents of ther hash in an array. Within this function that I am building I am entering in the data in the hash in the form last name, firstname, age. When the value is returned I want the value to come out of the array age,firstname, lastname. I also tyring to get it to sort. Since I know more about sorting arrays I was thinking of just sorting the array instead of the hash. Right now, the info is not reading the hash correctly. This is what I have code wise:

%people = ("Richardson, Greg" -> 22, "Zog, Mike" -> 23, "Boston, Doug -> 24, "Rudolph, Josh" -> 25, "Fritz, Stacy" -> 26)

foreach @child (keys %people) {
print "$child, $people{$child}

@people = keys %people, values %people
@sorted_people = sort{lc($b) cmp (lc($a)} @people
print @sorted_people

Any help would be great

Question by:DancingFighterG

Expert Comment

ID: 9660011
You can actually sort the hash without creating an array.  Try this:

%people = ("Richardson, Greg" -> 22, "Zog, Mike" -> 23, "Boston, Doug -> 24, "Rudolph, Josh" -> 25, "Fritz, Stacy" -> 26)

foreach ( sort { lc($b) cmp lc($a)}  keys (%people) ) {

      my @names = split /, /;
      my $age = $people{$_};


so $names[0] will have the last name, and $names[1] will contain the first name.
LVL 28

Expert Comment

ID: 9661184
ultimatemike showed you an excelent method for for doing the sort (in reverse order).  However, instead of splitting the name into an array, I'd use 2 scalars and I'd make sure the names were translated to titlecase.  My example uses to print statements to show the difference in style of output.

%people = ("richardson, greg" => 22, "Zog, Mike" => 23, "Boston, doug" => 24, "Rudolph, Josh" => 25, "Fritz, Stacy" => 26);

foreach $person ( sort { lc($a) cmp lc($b)}  keys (%people) ) {

   $person =~ s/(\w+)/\u$1/g;  # translate to titlecase
   ($last, $first) = split /, /, $person;

   print "$person is $people{$person} years old\n";
   print "$first $last is $people{$person} years old\n\n";
LVL 28

Expert Comment

ID: 9661235
If you really need to use an array, then instead of those print statements, you'd push the info onto the array.

Like this:

push @last_first, "$person $people{$person}";
push @first_last, "$first $last $people{$person}";

Then you can print the array somewhere else in your script. like this:

print "$_\n" foreach @last_first;
print "$_\n" foreach @first_last;
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

LVL 18

Expert Comment

ID: 9662464
Why not change your data to another structure? I like using record-style hashes for this, because it adds flexibility in both sorting and displaying.
I would use something like:
$person = {
    firstname => 'Greg',
    lastname => 'Richardson',
    age         => 22

First I'll convert your %people hash into an array of person records:
my @people = ();
while(my ($k, $v) = each %people) {           # loop over elements
    my ($lname, $fname) = split /, /, $k, 2;    # split the key into name parts
    push @people, {                                      # add anonymous hash to the array
        firstname => $fname,
        lastname  => $lname,
         age         => $v

now you can sort your array on one or more keys of the records.

# sort by last name
my @ns_people = sort {
     $a->{lastname} cmp $b->{lastname}
    } @people;

# sort by last name, firstname ascending, age descending
my @lfa_people = sort {
     $a->{lastname} cmp $b->{lastname} ||        # first sort on last name
     $a->{firstname} cmp $b->{firstname} ||        # next on first name
     $b->{age}          <=> $a->{age}                   # finally, on age descending
    } @people;

you can put whatever criteria into the sort { } block that you need. (Including doing a case insensitive sort).

Outputting your data becomes much more flexible too, since you have separate fields for every part of the person.
foreach(@lfa_people) {
    printf "Age: %d, name: %s %s\n", $_->{age}, $_->{firstname}, $_->{lastname};

Also it makes it easy to filter your data. Say you would only want the people with age 25:
@tf_people = grep { $_->{age} == 25 } @lfa_people;



Author Comment

ID: 9672884
Quick question FishMonger, is there any way I can print out the hash itself so I can show the original has data and then the array version?
LVL 20

Expert Comment

ID: 9673044
You could do

use Data::Dumper;

print Dumper( \%people, \@lfa_people);

LVL 28

Accepted Solution

FishMonger earned 150 total points
ID: 9673579
After looking over the script that I posted, I noticed an error I made reguarding the the titlecase.  Here's the corrected script that also prints out the hash before and after the sorting (as well as the sorted array) and uses the CSV formating (I think you were wanting) .

%people = (
           "richardson, greg" => 22,
           "zog, mike" => 23,
           "Boston, doug" => 24,
           "Rudolph, Josh" => 25,
           "Fritz, Stacy" => 26

print "Prior to sorting the hash\n";
print "\t$_ $people{$_}\n" foreach (keys %people);

print "\nAfter sorting the hash\n";
foreach $person ( sort { lc($a) cmp lc($b)}  keys (%people) ) {
   ($last, $first) = split /, /, $person;
   $last =~ s/(\w+)/\u$1/;  # translate to titlecase
   $first =~ s/(\w+)/\u$1/;  # translate to titlecase
   print "\t$people{$person},$first,$last\n";
   push @first_last, "$people{$person},$first,$last";

print "\nSorted hash put into an array\n";
print "\t$_\n" foreach @first_last;

Author Comment

ID: 9674633
Thanks FishMonger. I could not figure out how to print out the hash right. Thanks again. :)

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
There are many situations when we need to display the data in sorted order. For example: Student details by name or by rank or by total marks etc. If you are working on data driven based projects then you will use sorting techniques very frequently.…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

713 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question