• Sorting an array by two functions

    From Henry Law@21:1/5 to All on Sat Nov 27 10:34:31 2021
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Henry Law on Sat Nov 27 13:45:44 2021
    Henry Law <news@lawshouse.org> writes:
    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.

    Do you want elements with the same account code and different dates
    grouped together, or vice versa?

    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;

    The function has to return a value that's less than, equal to, or
    greater than zero. It doesn't have to be -1, 0, or +1 (though of course
    it can be, and "<=>" and "cmp" do so unless you use "<=>" with NaNs).
    See "perldoc perlop".

    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?

    No. Quoting "perldoc perlop":

    The "||", "//" and "&&" operators return the last value evaluated
    (unlike C's "||" and "&&", which return 0 or 1).

    (And note that Perl doesn't have TRUE and FALSE constants.)

    I don't know what the problem is. I'd probably use "or" rather than
    "||", or add parentheses, just for greater clarity, but "cmp" and "<=>"
    bind more tightly than either "||" or "or", so that's not the issue.

    If you don't get an answer from someone else, try showing us some sample
    data, the order you expect, and the order you're getting.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips
    void Void(void) { Void(); } /* The recursive call of the void */

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Henry Law on Mon Nov 29 17:52:56 2021
    Henry Law <news@lawshouse.org> writes:
    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?

    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);

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Henry Law@21:1/5 to Rainer Weikusat on Mon Nov 29 16:49:57 2021
    On Mon, 29 Nov 2021 17:52:56 +0000, Rainer Weikusat wrote:

    The code below works as expected:

    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
    than me dim enough to need an explanation:

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

    "||" 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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andrzej Adam Filip@21:1/5 to Henry Law on Tue Nov 30 00:15:24 2021
    Henry Law <news@lawshouse.org> wrote:
    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?

    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)