NAME
    Sort::BySpec - Sort array (or create a list sorter) according to
    specification

VERSION
    This document describes version 0.040 of Sort::BySpec (from Perl
    distribution Sort-BySpec), released on 2021-05-01.

SYNOPSIS
     use Sort::BySpec qw(sort_by_spec cmp_by_spec);

     my $sorter = sort_by_spec(spec => [
         # put odd numbers first, in ascending order
         qr/[13579]\z/ => sub { $_[0] <=> $_[1] },

         # then put specific numbers here, in this order
         4, 2, 42,

         # put even numbers last, in descending order
         sub { $_[0] % 2 == 0 } => sub { $_[1] <=> $_[0] },
     ]);

     my @res = $sorter->(1..15, 42);
     # => (1,3,5,7,9,11,13,15,  4,2,42,   14,12,10,8,6)

DESCRIPTION
    This package provides a more powerful alternative to Sort::ByExample.
    Unlike in `Sort::ByExample` where you only provide a single array of
    example, you can specify multiple examples as well as regex or matcher
    subroutine coupled with sort rules. With this, you can more precisely
    specify how elements of your list should be ordered. If your needs are
    not met by Sort::ByExample, you might want to consider this package. The
    downside is performance penalty, especially when your list is large.

    To sort using Sort::BySpec, you provide a "spec" which is an array of
    strings, regexes, or coderefs to match against elements of your list to
    be sorted. In the simplest form, the spec contains only a list of
    examples:

     my $sorter = sort_by_spec(spec => ["foo", "bar", "baz"]); # [1]

    and this is equivalent to Sort::ByExample:

     my $sorter = sbe(["foo", "bar", "baz"]);

    You can also specify regex to match elements. This is evaluated after
    strings, so this work:

     my $sorter = sort_by_spec(spec => [qr/o/, "foo", "bar", "baz", qr/a/]);
     my @list = ("foo", "food", "bar", "back", "baz", "fool", "boat");
     my @res = $sorter->(@list);
     # => ("food","boat","fool",   "foo","bar","baz",   "back")

    Right after a regex, you can optionally specify a sort subroutine to
    tell how to sort elements matching that regex, for example:

     my $sorter = sort_by_spec(spec => [
         qr/o/ => sub { $_[0] cmp $_[1] },
         "foo", "bar", "baz",
         qr/a/
     ]);

     # the same list @list above will now be sorted into:
     # => ("boat","food","fool",   "foo","bar","baz",   "back")

    Note that instead of $a and $b, you should use $_[0] and $_[1]
    respectively. This avoids the package scoping issue of $a and $b, making
    your sorter subroutine works everywhere without any special workaround.

    Finally, aside from strings and regexes, you can also specify a coderef
    matcher for more complex matching. Just like in the case of regex, right
    after the coderef you can optionally specify a sort subroutine (another
    coderef) to tell how to sort matching elements. For example:

     my $sorter = sort_by_spec(spec => [
         # put odd numbers first, in ascending order
         sub { $_[0] % 2 } => sub { $_[0] <=> $_[1] },

         # then put specific numbers here, in this order
         4, 2, 42,

         # put even numbers last, in descending order
         sub { $_[0] % 2 == 0 } => sub { $_[1] <=> $_[0] },
     ]);

     my @res = $sorter->(1..15, 42);
     # => (1,3,5,7,9,11,13,15,  4,2,42,   14,12,10,8,6)

FUNCTIONS
  cmp_by_spec
    Usage:

     cmp_by_spec(%args) -> code

    Create a compare subroutine to be used in sort().

    This function is not exported by default, but exportable.

    Arguments ('*' denotes required arguments):

    *   reverse => *bool*

        If set to true, will reverse the sort order.

    *   spec* => *array*

    *   xform => *code*

        Code to return sort keys from data elements.

        This is just like "xform" in "Sort::ByExample".

    Return value: (code)

  sort_by_spec
    Usage:

     sort_by_spec(%args) -> array|code

    Sort array (or create a list sorter) according to specification.

    Examples:

    *   Sort according to a sequence of scalars (like Sort::ByExample):

         sort_by_spec(
           spec  => ["foo", "bar", "baz"],
           array => [1, 2, 3, "bar", "a", "b", "c", "baz"]
         );

        Result:

         ["bar", "baz", 1, 2, 3, "a", "b", "c"]

    *   Like previous example, but reversed:

         sort_by_spec(
           spec    => ["foo", "bar", "baz"],
           array   => [1, 2, 3, "bar", "a", "b", "c", "baz"],
           reverse => 1
         );

        Result:

         ["bar", "baz", 1, 2, 3, "a", "b", "c"]

    *   Put integers first (in descending order), then a sequence of
        scalars, then others (in ascending order):

         sort_by_spec(
           spec  => [
                      qr/\A\d+\z/,
                      sub { $_[1] <=> $_[0] },
                      "foo",
                      "bar",
                      "baz",
                      qr//,
                      sub { $_[0] cmp $_[1] },
                    ],
           array => ["qux", "b", "a", "bar", "foo", 1, 10, 2]
         );

        Result:

         [10, 2, 1, "foo", "bar", "a", "b", "qux"]

    This function is not exported by default, but exportable.

    Arguments ('*' denotes required arguments):

    *   array => *array*

    *   reverse => *bool*

        If set to true, will reverse the sort order.

    *   spec* => *array*

    *   xform => *code*

        Code to return sort keys from data elements.

        This is just like "xform" in "Sort::ByExample".

    Return value: Sorted array, or sort coderef (array|code)

    If array is specified, will returned the sorted array. If array is not
    specified in the argument, will return a sort subroutine that can be
    used to sort a list and return the sorted list.

HOMEPAGE
    Please visit the project's homepage at
    <https://metacpan.org/release/Sort-BySpec>.

SOURCE
    Source repository is at <https://github.com/perlancar/perl-Sort-BySpec>.

BUGS
    Please report any bugs or feature requests on the bugtracker website
    <https://rt.cpan.org/Public/Dist/Display.html?Name=Sort-BySpec>

    When submitting a bug or request, please include a test-file or a patch
    to an existing test-file that illustrates the bug or desired feature.

SEE ALSO
    Sort::ByExample

    Bencher::Scenario::SortBySpec

AUTHOR
    perlancar <perlancar@cpan.org>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2021, 2017, 2015 by perlancar@cpan.org.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.