List-UtilsBy

 view release on metacpan or  search on metacpan

lib/List/UtilsBy.pm  view on Meta::CPAN

them "naturally", rather than lexically.

   sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings

This sorts strings by generating sort keys which zero-pad the embedded numbers
to some level (9 digits in this case), helping to ensure the lexical sort puts
them in the correct order.

=cut

sub sort_by(&@)
{
   my $keygen = shift;

   my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
   return @_[ sort { $keys[$a] cmp $keys[$b] } 0 .. $#_ ];
}

=head2 nsort_by

   @vals = nsort_by { KEYFUNC } @vals

Similar to L</sort_by> but compares its key values numerically.

=cut

sub nsort_by(&@)
{
   my $keygen = shift;

   my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
   return @_[ sort { $keys[$a] <=> $keys[$b] } 0 .. $#_ ];
}

=head2 rev_sort_by

=head2 rev_nsort_by

lib/List/UtilsBy.pm  view on Meta::CPAN

Similar to L</sort_by> and L</nsort_by> but returns the list in the reverse
order. Equivalent to

   @vals = reverse sort_by { KEYFUNC } @vals

except that these functions are slightly more efficient because they avoid
the final C<reverse> operation.

=cut

sub rev_sort_by(&@)
{
   my $keygen = shift;

   my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
   return @_[ sort { $keys[$b] cmp $keys[$a] } 0 .. $#_ ];
}

sub rev_nsort_by(&@)
{
   my $keygen = shift;

   my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
   return @_[ sort { $keys[$b] <=> $keys[$a] } 0 .. $#_ ];
}

=head2 max_by

   $optimal = max_by { KEYFUNC } @vals

lib/List/UtilsBy.pm  view on Meta::CPAN

list of all the maximal values is returned. This may be used to obtain
positions other than the first, if order is significant.

If called on an empty list, an empty list is returned.

For symmetry with the L</nsort_by> function, this is also provided under the
name C<nmax_by> since it behaves numerically.

=cut

sub max_by(&@)
{
   my $code = shift;

   return unless @_;

   local $_;

   my @maximal = $_ = shift @_;
   my $max     = $code->( $_ );

lib/List/UtilsBy.pm  view on Meta::CPAN


   $optimal = min_by { KEYFUNC } @vals

   @optimal = min_by { KEYFUNC } @vals

Similar to L</max_by> but returns values which give the numerically smallest
result from the key function. Also provided as C<nmin_by>

=cut

sub min_by(&@)
{
   my $code = shift;

   return unless @_;

   local $_;

   my @minimal = $_ = shift @_;
   my $min     = $code->( $_ );

lib/List/UtilsBy.pm  view on Meta::CPAN

I<Since version 0.11.>

Similar to calling both L</min_by> and L</max_by> with the same key function
on the same list. This version is more efficient than calling the two other
functions individually, as it has less work to perform overall. In the case of
ties, only the first optimal element found in each case is returned. Also
provided as C<nminmax_by>.

=cut

sub minmax_by(&@)
{
   my $code = shift;

   return unless @_;

   my $minimal = $_ = shift @_;
   my $min     = $code->( $_ );

   return ( $minimal, $minimal ) unless @_;

lib/List/UtilsBy.pm  view on Meta::CPAN


   my @some_fruit = reverse uniq_by { $_->colour } reverse @fruit;

Because the values returned by the key function are used as hash keys, they
ought to either be strings, or at least well-behaved as strings (such as
numbers, or object references which overload stringification in a suitable
manner).

=cut

sub uniq_by(&@)
{
   my $code = shift;

   my %present;
   return grep {
      my $key = $code->( local $_ = $_ );
      !$present{$key}++
   } @_;
}

lib/List/UtilsBy.pm  view on Meta::CPAN


   my %balls_by_colour = partition_by { $_->colour } @balls;

Because the values returned by the key function are used as hash keys, they
ought to either be strings, or at least well-behaved as strings (such as
numbers, or object references which overload stringification in a suitable
manner).

=cut

sub partition_by(&@)
{
   my $code = shift;

   my %parts;
   push @{ $parts{ $code->( local $_ = $_ ) } }, $_ for @_;

   return %parts;
}

=head2 count_by

lib/List/UtilsBy.pm  view on Meta::CPAN


   my %count_of_balls = count_by { $_->colour } @balls;

Because the values returned by the key function are used as hash keys, they
ought to either be strings, or at least well-behaved as strings (such as
numbers, or object references which overload stringification in a suitable
manner).

=cut

sub count_by(&@)
{
   my $code = shift;

   my %counts;
   $counts{ $code->( local $_ = $_ ) }++ for @_;

   return %counts;
}

=head2 zip_by

lib/List/UtilsBy.pm  view on Meta::CPAN

a hash from two separate lists of keys and values

   my %nums = zip_by { @_ } [qw( one two three )], [ 1, 2, 3 ];
   # %nums = ( one => 1, two => 2, three => 3 )

(A function having this behaviour is sometimes called C<zipWith>, e.g. in
Haskell, but that name would not fit the naming scheme used by this module).

=cut

sub zip_by(&@)
{
   my $code = shift;

   @_ or return;

   my $len = 0;
   scalar @$_ > $len and $len = scalar @$_ for @_;

   return map {
      my $idx = $_;

lib/List/UtilsBy.pm  view on Meta::CPAN

   my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names;

If the function returns lists of differing lengths, the result will be padded
with C<undef> in the missing elements.

This function is an inverse of L</zip_by>, if given a corresponding inverse
function.

=cut

sub unzip_by(&@)
{
   my $code = shift;

   my @ret;
   foreach my $idx ( 0 .. $#_ ) {
      my @slice = $code->( local $_ = $_[$idx] );
      $#slice = $#ret if @slice < @ret;
      $ret[$_][$idx] = $slice[$_] for 0 .. $#slice;
   }

lib/List/UtilsBy.pm  view on Meta::CPAN

   extract_by { !defined $_ } @refs;

will leave weak references weakened in the C<@refs> array, whereas

   @refs = grep { defined $_ } @refs;

will strengthen them all again.

=cut

sub extract_by(&\@)
{
   my $code = shift;
   my ( $arrref ) = @_;

   my @ret;
   for( my $idx = 0; ; $idx++ ) {
      last if $idx > $#$arrref;
      next unless $code->( local $_ = $arrref->[$idx] );

      push @ret, splice @$arrref, $idx, 1, ();

lib/List/UtilsBy.pm  view on Meta::CPAN

As with L</extract_by>, this function requires a real array and not just a
list, and is also implemented using C<splice> so that weak references are
not disturbed.

If this function fails to find a matching element, it will return an empty
list in list context. This allows a caller to distinguish the case between
no matching element, and the first matching element being C<undef>.

=cut

sub extract_first_by(&\@)
{
   my $code = shift;
   my ( $arrref ) = @_;

   foreach my $idx ( 0 .. $#$arrref ) {
      next unless $code->( local $_ = $arrref->[$idx] );

      return splice @$arrref, $idx, 1, ();
   }

lib/List/UtilsBy.pm  view on Meta::CPAN


I<Since version 0.07.>

Returns the list of values shuffled into a random order. The randomisation is
not uniform, but weighted by the value returned by the C<WEIGHTFUNC>. The
probability of each item being returned first will be distributed with the
distribution of the weights, and so on recursively for the remaining items.

=cut

sub weighted_shuffle_by(&@)
{
   my $code = shift;
   my @vals = @_;

   my @weights = map { $code->( local $_ = $_ ) } @vals;

   my @ret;
   while( @vals > 1 ) {
      my $total = 0; $total += $_ for @weights;
      my $select = int rand $total;

lib/List/UtilsBy.pm  view on Meta::CPAN


Similar to a regular C<map> functional, returns a list of the values returned
by C<BLOCKFUNC>. Values from the input list are given to the block function in
bundles of C<$number>.

If given a list of values whose length does not evenly divide by C<$number>,
the final call will be passed fewer elements than the others.

=cut

sub bundle_by(&@)
{
   my $code = shift;
   my $n = shift;

   my @ret;
   for( my ( $pos, $next ) = ( 0, $n ); $pos < @_; $pos = $next, $next += $n ) {
      $next = @_ if $next > @_;
      push @ret, $code->( @_[$pos .. $next-1] );
   }
   return @ret;

t/Unrandom.pm  view on Meta::CPAN


use Exporter 'import';
our @EXPORT = qw( unrandomly );

our $randhook;
*CORE::GLOBAL::rand = sub { $randhook ? $randhook->( $_[0] ) : rand $_[0] };

use constant VALUE => 0;
use constant BELOW => 1;

sub unrandomly(&)
{
   my $code = shift;

   my @rands;
   my $randidx;
   local $randhook = sub {
      my ( $below ) = @_;
      if( $randidx > $#rands ) {
         push @rands, [ 0, $below ];
         $randidx++;



( run in 2.109 seconds using v1.01-cache-2.11-cpan-49f99fa48dc )