Re: Notation of sort function
by hippo (Archbishop) on Oct 27, 2023 at 09:46 UTC
|
It's a good question. There are cases where one might want to apply different conditions on the operands or where one of the operands isn't $a or $b at all. These cases are rare but they do crop up from time to time.
I have had a trawl through some code of mine and haven't found one yet. Closest I have is this:
@abc = sort { length ($b) <=> length ($a) || $a cmp $b } @abc;
Even through here we are treating $a and $b in the same way, I don't know how you would express this without the flexibility that the current syntax gives. It would not be as succinct, that's for sure.
| [reply] [d/l] |
|
Hello all,
Alphaphi: I dont see redundancy, I think the syntax is flexible to permit also different use cases.
hippo:
> There are cases where one might want to apply different conditions on the operands..
mmh.. yes this can also be true but I suppose just as a trigger inside comparison: which apple is heavier but golden one count more
use strict;
use warnings;
use Data::Dump;
my %apples = (
one => { weight => 10, golden=> 0},
two => { weight => 20, golden=> 0},
three => { weight => 5 , golden=> 1},
);
my @sorted = sort{ (
$apples{$b}->{golden} ?
$apples{$b}->{weight} * 10 :
$apples{$b}->{weight}
)
<=>
(
$apples{$a}->{golden} ?
$apples{$a}->{weight} * 10 :
$apples{$a}->{weight}
)
}keys %apples;
dd @sorted;
__END__
("three", "two", "one")
> ..or where one of the operands isn't $a or $b at all
I dont think this can be logic.
Also in sort of misunderstanding of sort you can find that sort is optimized, so not every pair is checked so if you will sort apple against pear I wonder which use case can be.
Courious to know otherwise :)
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
|
#!/usr/bin/env perl
use strict;
use warnings;
my @words = qw/The omega quick brown omega fox jumps over the omega la
+zy dog/;
my @sorted = sort { $a eq 'omega' ? 1 : -1 } @words;
print "@sorted\n";
This moves all the 'omega' entries to the end of the array but the other entries are not predictably sorted. Not something you are going to need every day but useful to have in the toolbox for those rare occasions which call for it.
| [reply] [d/l] |
|
This is a good example for redundancy. Why not like this:
my @sorted = sort{
{
$apples{$SORTVAR}->{golden} ?
$apples{$SORTVAR}->{weight} * 10 :
$apples{$SORTVAR}->{weight}
},
'<=>'
} keys %apples;
Here I specify the calculation to be performed only once, and as a second parameter, I pass the operator. | [reply] [d/l] |
|
|
|
Re: Notation of sort function
by hv (Prior) on Oct 27, 2023 at 13:49 UTC
|
Note in particular this fragment from near the end of the docs for sort:
The comparison function is required to behave. If it returns inconsistent results (sometimes saying $x[1] is less than $x[2] and sometimes saying the opposite, for example) the results are not well-defined.
"Consistent" means, for example, that if your comparison function says A > B, then it should also say B < A if called with the arguments the other way round. A comparator that specifies something different for $a than for $b will almost certainly not be consistent, and should be avoided.
As others have noted, the apparent redundancy stems from having the most general possible form of comparator - a piece of code that does the comparison. Some of the standard special forms such as the Schwartzian Transform (ST) and the Guttman-Rosler Transform (GRT) also have the side effect of reducing the redundancy. For more information on those see the excellent set of links at 11135952 provided by eyepopslikeamosquito.
| [reply] [d/l] [select] |
Re: Notation of sort function
by haj (Vicar) on Oct 27, 2023 at 10:54 UTC
|
I have no example at hand where the two operands would be treated differently. However, this isn't as redundant as it might look. Syntactically, it is an expression with a binary comparison operator. This can be parsed and executed as a code block by the Perl interpreter. If you want to avoid specifying one of the operands you'd need a new syntax where you can specify a function operating on one of the values from the list, a comparison operator, and also, whether you want ascending or descending order. But such a syntax doesn't cover all use cases: You can also compare like sort {my_function($a,$b)} which has no redundancy, and no visible comparison operator.
| [reply] |
Re: Notation of sort function
by GrandFather (Saint) on Oct 30, 2023 at 22:15 UTC
|
$a and $b are place holders for pairs of values from a list that the sort algorithm wants to determine the relative order of. Testing a single value (except in something like Hippo's example) doesn't make sense. In the vast majority of cases we want sort to order a list according to some predicate that determines the ordering of two elements. Hippo's example really just groups elements into two buckets rather than sorting them in a conventional sense.
Bottom line, sort orders a list by some process that compares pairs of elements from the list. There is no redundancy using a pair of variables.
Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
| [reply] |
Re: Notation of sort function
by jwkrahn (Abbot) on Oct 27, 2023 at 18:16 UTC
|
Perl's sort comparison function is sort of based on C's sort comparison function.
The only thing that Perl's sort requires is that the function returns a negative number, zero or a positive number. You can use the <=> or cmp operators or any other method you choose.
Update:
For example:
$ perl -MList::Util=shuffle -le'
my @x = shuffle 1 .. 20;
print "@x";
my @y = sort { $a <=> $b } @x;
print "@y";
my @z = sort { $a - $b } @x;
print "@z"
'
7 10 16 20 14 15 4 18 19 17 6 5 8 9 2 13 1 3 11 12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$ perl -MList::Util=shuffle -le'
my @x = shuffle -10 .. 10;
print "@x";
my @y = sort { $a <=> $b } @x;
print "@y";
my @z = sort { $a - $b } @x;
print "@z"
'
-1 -7 -4 1 4 -9 10 -3 0 -8 -6 -2 8 -10 5 6 9 -5 2 3 7
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10
-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10
Naked blocks are fun!
-- Randal L. Schwartz, Perl hacker
| [reply] [d/l] |
Re: Notation of sort function
by ikegami (Patriarch) on Oct 27, 2023 at 19:08 UTC
|
Is there a case in which we would specify something else for $a than for $b?
No.
And worse, you're calculating that value n * log2(n) * 2 times.
Sort::Key and related modules provide an interface where the key is only calculated n times.
| [reply] |
Re: Notation of sort function
by Jenda (Abbot) on Oct 28, 2023 at 15:44 UTC
|
Because we are not just specifying what part(s) of the elements do we want to compare, but also how!
cmp may be fine for you English speaking dudes, but it's basically useless to the rest of the world. Besides even if we did keep to cmp and <=>, what's some other, reasonably succinct and reasonably comprehensible way to write sort {$a->{age} <=> $a->{age} || $b->{name} cmp $a->{name}} @array ?
What is the operation you'd want to apply to the elements so that you can then sort the results using one of the only two types of comparisons you seem to want to get restricted to?
Jenda
1984 was supposed to be a warning,
not a manual!
| [reply] [d/l] [select] |
Re: Notation of sort function (Sort::Key)
by LanX (Saint) on Oct 27, 2023 at 13:49 UTC
|
You are right it's in >99% of the cases redundant.
IMHO it doesn't really matter what other cases are, what matters is that they are extremely rare.
That's why another approach is sorting with "key functions", which is not only shorter but also faster.
tldr
For a deeper understanding it's worth looking over the fence.
Python (among other languages) has key functions and Salva implemented them with Sort::Key.
But why does Salva's implementation provide a zoo of different functions making it more difficult to grasp?
Because comparisons in Perl are operator based while Python is typed based. (There is no eq in Python, a value is a string or not)
Hence Salva needs to implement keysort nkeysort to reflect the differences between == and eq ... In Python they rely on the implicit type.
And he needs rkeysort rnkeysort to reverse the sort order.
IMHO
A perfect solution in Perl would involve an additional Sort::Key like solution, with a syntax reusing the established operators cmp and <=> plus an easy way to indicate reversing the sort order.
| [reply] [d/l] [select] |
Re: Notation of sort function
by Polyglot (Chaplain) on Oct 27, 2023 at 08:21 UTC
|
I'm not the Perl guru that some folk here are, but my understanding of the $a and $b tokens is that they represent two items in the list which must be compared against each other in order to know which should come first in the list. If you had only one item to compare, the list would not be sorted at all, because each item would stay in the same place. The only way to sort is by shifting positions of two items at a time, until the entire list is properly sequenced. The specifications given for the $a and $b simply define what features one wishes to consider when comparing. Do you, for example, wish to rank them by their numerical value? by their string length? by their alphabetical order? ... and so on.
If $a only gets compared to $a, it will not move--and the list will remain unchanged. Sorting only means anything if each item gets compared to another one. On the other hand, it would seem rather strange to compare, for ranking purposes, the numerical value of one item with the string length of another--and the results of such a comparison, if Perl allowed it (I don't know if it would or not), would probably look rather illogical.
| [reply] |
Re: Notation of sort function
by BillKSmith (Monsignor) on Oct 28, 2023 at 12:58 UTC
|
In the truly redundant cases, you can use the sort_by function from List::UtilsBy
| [reply] [d/l] |