NAME

Sort::ByExample - sort lists to look like the example you provide

VERSION

version 0.008

SYNOPSIS

  use Sort::ByExample
   cmp    => { -as => 'by_eng',   example => [qw(first second third fourth)] },
   sorter => { -as => 'eng_sort', example => [qw(first second third fourth)] };

  my @output = eng_sort(qw(second third unknown fourth first));
  # --> first second third fourth unknown

  # ...or...

  my @output = sort by_eng qw(second third unknown fourth first);
  # --> first second third fourth unknown

  # ...or...

  my $sorter = Sort::ByExample::sbe(\@example);
  my @output = $sorter->( qw(second third unknown fourth first) );
  # --> first second third fourth unknown

  # ...or...

  my $example = [ qw(charlie alfa bravo) ];
  my @input   = (
    { name => 'Bertrand', codename => 'bravo'   },
    { name => 'Dracover', codename => 'zulu',   },
    { name => 'Cheswick', codename => 'charlie' },
    { name => 'Elbereth', codename => 'yankee'  },
    { name => 'Algernon', codename => 'alfa'    },
  );

  my $fallback = sub {
    my ($x, $y) = @_;
    return $x cmp $y;
  };

  my $sorter = sbe(
    $example,
    {
      fallback => $fallback,
      xform    => sub { $_[0]->{codename} },
    },
  );

  my @output = $sorter->(@input);

  # --> (
  #       { name => 'Cheswick', codename => 'charlie' },
  #       { name => 'Algernon', codename => 'alfa'    },
  #       { name => 'Bertrand', codename => 'bravo'   },
  #       { name => 'Elbereth', codename => 'yankee'  },
  #       { name => 'Dracover', codename => 'zulu',   },
  #     );

DESCRIPTION

Sometimes, you need to sort things in a pretty arbitrary order. You know that you might encounter any of a list of values, and you have an idea what order those values go in. That order is arbitrary, as far as actual automatic comparison goes, but that's the order you want.

Sort::ByExample makes this easy: you give it a list of example input it should expect, pre-sorted, and it will sort things that way. If you want, you can provide a fallback sub for sorting unknown or equally-positioned data.

PERL VERSION

This library should run on perls released even a long time ago. It should work on any version of perl released in the last five years.

Although it may work on older versions of perl, no guarantee is made that the minimum required version will not be increased. The version may be increased for any reason, and there is no promise that patches will be accepted to lower the minimum required perl.

METHODS

sorter

  my $sorter = Sort::ByExample->sorter($example, $fallback);
  my $sorter = Sort::ByExample->sorter($example, \%arg);

The sorter method returns a subroutine that will sort lists to look more like the example list.

$example may be a reference to an array, in which case input will be sorted into the same order as the data in the array reference. Input not found in the example will be found at the end of the output, sorted by the fallback sub if given (see below).

Alternately, the example may be a reference to a hash. Values are used to provide sort orders for input values. Input values with the same sort value are sorted by the fallback sub, if given.

If given named arguments as %arg, valid arguments are:

  fallback - a sub to sort data
  xform    - a sub to transform each item into the key to sort

If no other named arguments are needed, the fallback sub may be given in place of the arg hashref.

The fallback sub should accept two inputs and return either 1, 0, or -1, like a normal sorting routine. The data to be sorted are passed as parameters. For uninteresting reasons, $a and $b can't be used.

The xform sub should accept one argument and return the data by which to sort that argument. In other words, to sort a group of athletes by their medals:

  my $sorter = sbe(
    [ qw(Gold Silver Bronze) ],
    {
      xform => sub { $_[0]->medal_metal },
    },
  );

If both xform and fallback are given, then four arguments are passed to fallback:

  a_xform, b_xform, a_original, b_original

cmp

  my $comparitor = Sort::ByExample->cmp($example, \%arg);

This routine expects the same sort of arguments as "sorter", but returns a subroutine that behaves like a sort comparitor. It will take two arguments and return 1, 0, or -1.

cmp must not be given an xform argument or an exception will be raised. This behavior may change in the future, but because a single-comparison comparitor cannot efficiently perform a Schwartzian transform, using a purpose-build "sorter" is a better idea.

EXPORTS

sbe

sbe behaves just like "sorter", but is a function rather than a method. It may be imported by request.

sorter

The sorter export builds a function that behaves like the sorter method.

cmp

The cmp export builds a function that behaves like the cmp method. Because sort requires a named sub, importing cmp can be very useful:

  use Sort::ByExample
   cmp    => { -as => 'by_eng',   example => [qw(first second third fourth)] };

  my @output = sort by_eng qw(second third unknown fourth first);
  # --> first second third fourth unknown

TODO

  • provide a way to say "these things occur after any unknowns"

AUTHOR

Ricardo SIGNES <cpan@semiotic.systems>

CONTRIBUTORS

  • Olaf Alders <olaf@wundersolutions.com>

  • Ricardo Signes <rjbs@semiotic.systems>

COPYRIGHT AND LICENSE

This software is copyright (c) 2007 by Ricardo SIGNES.

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