In this article, we learn how to use Perl to sort strings or arrays of numbers.
Perl has a built-in function called sort that can undoubtedly sort an array. Its simplest form is to pass an array, which returns an array composed of sorted elements. @sorted = sort @original.
Based on ASCII code sorting
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper qw(Dumper);
my @words = qw(foo bar zorg moo);
say Dumper \@words;
my @sorted_words = sort @words;
say Dumper \@sorted_words;
The above example will be printed
$VAR1 = [
'foo',
'bar',
'zorg',
'moo'
];
$VAR1 = [
'bar',
'foo',
'moo',
'zorg'
];
The first output shows the array before sorting, and the second is after sorting.
This is the easiest case, but it may not be what you want. For example, what if some words start with capital letters?
my @words = qw(foo bar Zorg moo);
The result in @sorted_names will be:
$VAR1 = [
'Zorg',
'bar',
'foo',
'moo'
];
You will find that words starting with capital letters come first. This is because sort is sorted by ASCII code table by default, and all uppercase letters are ranked before lowercase letters.
Comparison function
Perl's sort works like this, it traverses every two elements of the original array; each time put the left value into the variable $a and the right value into the variable $b. Then call the comparison function. If the content of $a should be on the left, the "compare function" will return 1; if $b should be on the left, it will return -1, and if both are the same, it will return 0.
Usually you don't see the comparison function, sort will compare the values based on the ASCII code table, but if you want, you can write it explicitly:
sort { $a cmp $b } @words;
This code will achieve the same effect as sort @words without blocks.
Here you can see that by default perl uses cmp as the comparison function. This is because cmp can do the work we need here. It compares the values of strings on both sides. If the left parameter is "less than" the right parameter, it returns 1; if the left parameter is "greater than" the right parameter, it returns -1; if it is equal, it returns 0.
Alphabetical order
If you want to ignore the case of strings to sort - commonly known as alphabetical order, you can do it like the next example:
my @sorted_words = sort { lc($a) cmp lc($b) } @words;
For comparison here, we call the lc function to return the lowercase version of the parameter. Then cmp compares these lowercase versions and decides who comes first and who comes after the original string.
turn out
$VAR1 = [
'bar',
'foo',
'moo',
'Zorg'
];
Perl logarithmic sorting
If you use sort on the numeric array to perform default sorting, the result may not be what we expect.
my @numbers = (14, 3, 12, 2, 23);
my @sorted_numbers = sort @numbers;
say Dumper \@sorted_numbers;
$VAR1 = [
12,
14,
2,
23,
3
];
If you think about it carefully, it is not surprising. When the comparison function sees 12 and 3, it compares by string. This means comparing the first characters "1" and "3" of two strings. In the ASCII code table, "1" is before "3", so the string "12" will be before the string "3".
Perl won't magically guess that you want to sort these values by numbers.
Although we can write a comparison function to compare two values by number. But here we use <=> (also known as the spaceship operator), which compares two parameters by numbers and returns 1, -1, or 0.
my @sorted_numbers = sort { $a <=> $b } @numbers;
turn out:
$VAR1 = [
2,
3,
12,
14,
23
];