| Search perlmeme.org | |
| Home » Tutorials » Sort function |
The sort function sorts a list (an array). The default is to sort alphabetically. However, you can define your own sorts to get around numbers and complex data structures.
#!/usr/bin/perl
use strict;
use warnings;
my @strings = ("Becky", "Simon", "Bianca", "Steven", "Greg", "Andrew");
my @sorted_strings = sort @strings;
print "@sorted_strings\n";
This gives you the following output:
Andrew Becky Bianca Greg Simon Steven
The Perl sort function sorts by strings instead of by numbers. If you were to use:
#!/usr/bin/perl
use strict;
use warnings;
my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);
my @sorted_numbers = sort @numbers;
print "@sorted_numbers\n";
The output you would see would be:
1 109 22 23 3 65 7 9
To sort numerically, declare your own sort block and use the flying saucer operator <=>:
#!/usr/bin/perl
use strict;
use warnings;
my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);
my @sorted_numbers = sort {$a <=> $b} @numbers;
print "@sorted_numbers\n";
The output would now be:
1 3 7 9 22 23 65 109
Note that $a and $b do not need to be declared, even with use strict on, because they are special sorting variables.
To sort backwards you need to declare your own sort block, and simply put $b before $a.
For example, the standard sort is as follows:
#!/usr/bin/perl
use strict;
use warnings;
my @strings = ("Becky", "Simon", "Bianca", "Steven", "Greg", "Andrew");
my @sorted_strings = sort @strings;
print "@sorted_strings\n";
The output would be:
Andrew Becky Bianca Greg Simon Steven
To do the same, but in reverse order:
#!/usr/bin/perl
use strict;
use warnings;
my @strings = ("Becky", "Simon", "Bianca", "Steven", "Greg", "Andrew");
my @sorted_strings = sort {$b cmp $a} @strings;
print "@sorted_strings\n";
The output is:
Steven Simon Greg Bianca Becky Andrew
And for numbers:
#!/usr/bin/perl
use strict;
use warnings;
my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);
my @sorted_numbers = sort {$b <=> $a} @numbers;
print "@sorted_numbers\n";
The output is:
109 65 23 22 9 7 3 1
Of course, in both these cases there is another way:
#!/usr/bin/perl
use strict;
use warnings;
my @strings = ("Becky", "Simon", "Bianca", "Steven", "Greg", "Andrew");
my @sorted_strings = reverse sort @strings;
print "@sorted_strings\n";
The output is:
Steven Simon Greg Bianca Becky Andrew
And
#!/usr/bin/perl
use strict;
use warnings;
my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);
my @sorted_numbers = reverse sort {$a <=> $b} @numbers;
print "@sorted_numbers\n";
The output is:
109 65 23 22 9 7 3 1
You can use sort to order hashes. For example, if you had a hash as follows:
#!/usr/bin/perl
use strict;
use warnings;
my %data = (
bananas => 1,
oranges => 7,
apples => 12,
mangoes => 3,
pears => 8,
);
And you wanted to display the fruit sorted alphabetically, you could do this:
#!/usr/bin/perl
use strict;
use warnings;
my %data = (
bananas => 1,
oranges => 7,
apples => 12,
mangoes => 3,
pears => 8,
);
foreach my $fruit (sort keys %data) {
print $fruit . ": " . $data{$fruit} . "\n";
}
Output:
apples: 12
bananas: 1
mangoes: 3
oranges: 7
pears: 8
If you wanted to sort the same hash by the values (i.e. the number beside each fruit), you could do the following:
#!/usr/bin/perl
use strict;
use warnings;
my %data = (
bananas => 1,
oranges => 7,
apples => 12,
mangoes => 3,
pears => 8,
);
# Using <=> instead of cmp because of the numbers
foreach my $fruit (sort {$data{$a} <=> $data{$b}} keys %data) {
print $fruit . ": " . $data{$fruit} . "\n";
}
Output:
bananas: 1
mangoes: 3
oranges: 7
pears: 8
apples: 12
You can also use sort to sort more complex data strucutes. For example, if you had an array of hashes:
my @people = (
{ name => 'Becky', age => 23},
{ name => 'Simon', age => 43},
{ name => 'Bianca', age => 29},
{ name => 'Steven', age => 23},
{ name => 'Greg', age => 50},
{ name => 'Andrew', age => 19},
);
And you wish to display the data about the uses, in alphabetical order, you could do the following:
#!/usr/bin/perl
use strict;
use warnings;
my @people = (
{ name => 'Becky', age => 23},
{ name => 'Simon', age => 43},
{ name => 'Bianca', age => 29},
{ name => 'Steven', age => 23},
{ name => 'Greg', age => 50},
{ name => 'Andrew', age => 19},
);
foreach my $person (sort {$a->{name} cmp $b->{name}} @people) {
print $person->{name} . " is " . $person->{age} . "\n";
}
The output is:
Andrew is 19
Becky is 23
Bianca is 29
Greg is 50
Simon is 43
Steven is 23
Rather than writing the code inline, you can also pass in a subroutine name. The subroutine needs to return an integer less than, equal to, or greater than 0. Do not modify the $a and $b variables as they are passed in by reference, and modifying them will probably confuse your sorting.
#!/usr/bin/perl
use strict;
use warnings;
my @people = (
{ name => 'Becky', age => 23},
{ name => 'Simon', age => 43},
{ name => 'Bianca', age => 29},
{ name => 'Steven', age => 23},
{ name => 'Greg', age => 50},
{ name => 'Andrew', age => 19},
);
foreach my $person (sort byage @people) {
print $person->{name} . " is " . $person->{age} . "\n";
}
sub byage {
$a->{age} <=> $b->{age};
}
The output would be:
Andrew is 19
Becky is 23
Steven is 23
Bianca is 29
Simon is 43
Greg is 50
To find out more, run the command:
perldoc -f sort