Another way to do it, while certainly not the most efficient, is to replace undefelements with a value guaranteed to both be the maximum value in the comparison and uniquely distinct from the original value set.
I show this inefficient technique more to sow seeds for inspiration for future problems you may run into where setting a maximum value might be a useful idea. Data transmogrification still has value in some cases; having that tool in your toolshed is useful.
Coupled with the approach used by LanX, you could probably craft a fairly efficient and reliable version of this approach.
In this example, I convert the original array such that undefelements are replaced with a unique identifier guaranteed to sort to the bottom of the list (based on the assumption this is a string comparison); the replacement string is guaranteed to not have been found in the original array (again, via an inefficient technique -- I force it to be longer than the longest element in the original array).
From there, the rest of the operation should be relatively intuitive.
#!/usr/bin/perl
use strict;
use warnings;
# Constants (Operationally, if not functionally)
my $MAXCHR = chr 255;
my $HORRUL = '--------------------------------------------------------
+-----------------------';
# Globals
my $Maxval = '';
my @Unsorted = ( 'Dog', 'Cat', 'Bird', undef, 'Elephant', undef, 'Liza
+rd' );
dumpArray("Original:", @Unsorted);
# Build a maximum-value scalar: Length = longest + 1
# We will temporarily replace all undefined elements with this value
# Since it is composed of all chr 255 values, it is the highest for so
+rt
# Since it is one character longer than the longest element, it unique
+ly
# identifies the element as a former undef
# Then sort can do its thing and we can detect these to convert back t
+o undef
my $maxlen = longestElement(@Unsorted);
while (length($Maxval) <= $maxlen) {
$Maxval .= $MAXCHR;
}
# Build a working copy of the array with undef replaced by $Maxval
my @unsortedWork = ();
foreach (@Unsorted) {
if (defined $_) {
push @unsortedWork, $_;
} else {
push @unsortedWork, $Maxval;
}
}
# Sort, Convert modified entries back to undef, and show results
my @sorted_custom = sort @unsortedWork;
my @sorted_final = ();
foreach (@sorted_custom) {
if ($_ eq $Maxval) {
push @sorted_final, undef;
} else {
push @sorted_final, $_;
}
}
dumpArray("Custom Sort:", @sorted_final);
exit;
# Display an array with a title
sub dumpArray {
my ($dumpTitle, @dumpValues) = @_;
print "$HORRUL\n$dumpTitle\n$HORRUL\n";
foreach my $dumpValue (@dumpValues) {
if (defined $dumpValue) {
print "$dumpValue\n";
} else {
print "(undef)\n";
}
}
print "$HORRUL\n";
}
sub longestElement {
my $maxlen = 0;
foreach(@_) {
if (defined $_) {
if (length > $maxlen) { $maxlen = length; }
}
}
return $maxlen;
}
Results:
S:\Steve\Dev\PerlMonks\P-2017-06-12@0734-sort-undef>sort1.pl
----------------------------------------------------------------------
+---------
Original:
----------------------------------------------------------------------
+---------
Dog
Cat
Bird
(undef)
Elephant
(undef)
Lizard
----------------------------------------------------------------------
+---------
----------------------------------------------------------------------
+---------
Custom Sort:
----------------------------------------------------------------------
+---------
Bird
Cat
Dog
Elephant
Lizard
(undef)
(undef)
----------------------------------------------------------------------
+---------
S:\Steve\Dev\PerlMonks\P-2017-06-12@0734-sort-undef>
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.