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;
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

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

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
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…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

808 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