Discussion:
Sorting an array by two functions
(too old to reply)
Henry Law
2021-11-27 16:34:31 UTC
Permalink
I have an array of arrayrefs with this structure:

@array = ( [ '20100403', 'text', 'account code' ],
[ '19990503', 'text', 'other account code' ],
... etc )

I want to sort by account code and then by date. I read in various
places that the following will do the trick:

@array = sort { $a->[2] cmp $b->[2] || $a->[0] <=> $b->[0] } @array;

But I'm not getting the sort order I want. I know that the "sort"
function requires a three-valued return from the block, -1, 0 or +1; but
the "||" operator won't do that; it returns TRUE or FALSE.

Is that understanding correct? Is that the reason that I'm not getting
the order I want?
--
Henry Law n e w s @ l a w s h o u s e . o r g
Manchester, England
Rainer Weikusat
2021-11-29 17:52:56 UTC
Permalink
Post by Henry Law
@array = ( [ '20100403', 'text', 'account code' ],
[ '19990503', 'text', 'other account code' ],
... etc )
I want to sort by account code and then by date. I read in various
@array = sort { $a->[2] cmp $b->[2] || $a->[0] <=> $b->[0] } @array;
But I'm not getting the sort order I want. I know that the "sort"
function requires a three-valued return from the block, -1, 0 or +1; but
the "||" operator won't do that; it returns TRUE or FALSE.
Is that understanding correct? Is that the reason that I'm not getting
the order I want?
The code below works as expected:

-----
my @a;

for (reverse('a' .. 'z'), 'a' .. 'z') {
push(@a, [$_, int(rand(10))]);
}

sub pa
{
print($$_[0], "\t", $$_[1], "\n") for @_;
}

my @b = sort { $$a[0] cmp $$b[0] || $$a[1] <=> $$b[1] } @a;

pa(@b);
Henry Law
2021-11-29 22:49:57 UTC
Permalink
Indeed it does; and so does mine now that I've found the unrelated
mistake.

And I understand the error in my original reasoning. For anyone other
"||" operator returns the last value evaluated (see perlop); so if the
first comparison comes up zero and the second as, say, -1, the "||"
operation becomes 0 || -1; the result is -1 and the sort is satisfied.

I thought it would be restricted to 0 or 1, as in C; perlop clearly draws
attention to this distinction.
--
Henry Law n e w s @ l a w s h o u s e . o r g
Manchester, England
Andrzej Adam Filip
2021-11-30 00:15:24 UTC
Permalink
Post by Henry Law
@array = ( [ '20100403', 'text', 'account code' ],
[ '19990503', 'text', 'other account code' ],
... etc )
I want to sort by account code and then by date. I read in various
@array = sort { $a->[2] cmp $b->[2] || $a->[0] <=> $b->[0] } @array;
But I'm not getting the sort order I want. I know that the "sort"
function requires a three-valued return from the block, -1, 0 or +1; but
the "||" operator won't do that; it returns TRUE or FALSE.
Is that understanding correct? Is that the reason that I'm not getting
the order I want?
man perlop
The "||", "//" and "&&" operators return the last value evaluated
(unlike C's "||" and "&&", which return 0 or 1).

One-liner below produces "-1-1" :
perl -e 'print( -1 || 0, 0||-1)'
--
[Andrew] Andrzej A. Filip
Loading...