Hello community, here is the log from the commit of package perl-List-UtilsBy for openSUSE:Factory checked in at 2018-02-10 17:53:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-List-UtilsBy (Old) and /work/SRC/openSUSE:Factory/.perl-List-UtilsBy.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-List-UtilsBy" Sat Feb 10 17:53:51 2018 rev:2 rq:573768 version:0.11 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-List-UtilsBy/perl-List-UtilsBy.changes 2016-07-15 12:53:03.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.perl-List-UtilsBy.new/perl-List-UtilsBy.changes 2018-02-10 17:53:54.093397177 +0100 @@ -1,0 +2,13 @@ +Wed Feb 7 15:44:26 UTC 2018 - [email protected] + +- updated to 0.11 + see /usr/share/doc/packages/perl-List-UtilsBy/Changes + + 0.11 2018-01-31 23:12:44 + [CHANGES] + * Added 'minmax_by' (RT124275) + + [BUGFIXES] + * use lib '.' for 5.26+ (RT120418) + +------------------------------------------------------------------- Old: ---- List-UtilsBy-0.10.tar.gz New: ---- List-UtilsBy-0.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-List-UtilsBy.spec ++++++ --- /var/tmp/diff_new_pack.PtwT7V/_old 2018-02-10 17:53:55.389350264 +0100 +++ /var/tmp/diff_new_pack.PtwT7V/_new 2018-02-10 17:53:55.401349829 +0100 @@ -1,7 +1,7 @@ # # spec file for package perl-List-UtilsBy # -# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,14 +17,14 @@ Name: perl-List-UtilsBy -Version: 0.10 +Version: 0.11 Release: 0 %define cpan_name List-UtilsBy Summary: Higher-Order List Utility Functions License: Artistic-1.0 or GPL-1.0+ Group: Development/Libraries/Perl Url: http://search.cpan.org/dist/List-UtilsBy/ -Source0: http://www.cpan.org/authors/id/P/PE/PEVANS/%{cpan_name}-%{version}.tar.gz +Source0: https://cpan.metacpan.org/authors/id/P/PE/PEVANS/%{cpan_name}-%{version}.tar.gz Source1: cpanspec.yml BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -40,8 +40,8 @@ similar core perl or 'List::Util' functions of similar names, but which use the block to control their behaviour. For example, the core Perl function 'sort' takes a list of values and returns them, sorted into order by their -string value. The 'sort_by' function sorts them according to the string -value returned by the extra function, when given each value. +string value. The sort_by function sorts them according to the string value +returned by the extra function, when given each value. my @names_sorted = sort @names; @@ -63,6 +63,7 @@ %files -f %{name}.files %defattr(-,root,root,755) -%doc Changes LICENSE README +%doc Changes README +%license LICENSE %changelog ++++++ List-UtilsBy-0.10.tar.gz -> List-UtilsBy-0.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/Changes new/List-UtilsBy-0.11/Changes --- old/List-UtilsBy-0.10/Changes 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/Changes 2018-02-01 00:21:27.000000000 +0100 @@ -1,5 +1,12 @@ Revision history for List-UtilsBy +0.11 2018-01-31 23:12:44 + [CHANGES] + * Added 'minmax_by' (RT124275) + + [BUGFIXES] + * use lib '.' for 5.26+ (RT120418) + 0.10 2015/07/16 19:22:00 [CHANGES] * Added 'extract_first_by' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/LICENSE new/List-UtilsBy-0.11/LICENSE --- old/List-UtilsBy-0.10/LICENSE 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/LICENSE 2018-02-01 00:21:27.000000000 +0100 @@ -1,4 +1,4 @@ -This software is copyright (c) 2015 by Paul Evans <[email protected]>. +This software is copyright (c) 2018 by Paul Evans <[email protected]>. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. @@ -12,7 +12,7 @@ --- The GNU General Public License, Version 1, February 1989 --- -This software is Copyright (c) 2015 by Paul Evans <[email protected]>. +This software is Copyright (c) 2018 by Paul Evans <[email protected]>. This is free software, licensed under: @@ -272,7 +272,7 @@ --- The Artistic License 1.0 --- -This software is Copyright (c) 2015 by Paul Evans <[email protected]>. +This software is Copyright (c) 2018 by Paul Evans <[email protected]>. This is free software, licensed under: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/MANIFEST new/List-UtilsBy-0.11/MANIFEST --- old/List-UtilsBy-0.10/MANIFEST 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/MANIFEST 2018-02-01 00:21:27.000000000 +0100 @@ -10,8 +10,7 @@ t/00use.t t/01sort_by.t t/02nsort_by.t -t/03max_by.t -t/04min_by.t +t/03max_min_by.t t/05uniq_by.t t/06partition_by.t t/07count_by.t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/META.json new/List-UtilsBy-0.11/META.json --- old/List-UtilsBy-0.10/META.json 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/META.json 2018-02-01 00:21:27.000000000 +0100 @@ -4,13 +4,13 @@ "Paul Evans <[email protected]>" ], "dynamic_config" : 1, - "generated_by" : "Module::Build version 0.4211", + "generated_by" : "Module::Build version 0.422", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : "2" + "version" : 2 }, "name" : "List-UtilsBy", "prereqs" : { @@ -33,7 +33,7 @@ "provides" : { "List::UtilsBy" : { "file" : "lib/List/UtilsBy.pm", - "version" : "0.10" + "version" : "0.11" } }, "release_status" : "stable", @@ -42,5 +42,6 @@ "http://dev.perl.org/licenses/" ] }, - "version" : "0.10" + "version" : "0.11", + "x_serialization_backend" : "JSON::PP version 2.94" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/META.yml new/List-UtilsBy-0.11/META.yml --- old/List-UtilsBy-0.10/META.yml 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/META.yml 2018-02-01 00:21:27.000000000 +0100 @@ -7,7 +7,7 @@ configure_requires: Module::Build: '0.4004' dynamic_config: 1 -generated_by: 'Module::Build version 0.4211, CPAN::Meta::Converter version 2.150001' +generated_by: 'Module::Build version 0.422, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -16,9 +16,10 @@ provides: List::UtilsBy: file: lib/List/UtilsBy.pm - version: '0.10' + version: '0.11' requires: Exporter: '5.57' resources: license: http://dev.perl.org/licenses/ -version: '0.10' +version: '0.11' +x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/Makefile.PL new/List-UtilsBy-0.11/Makefile.PL --- old/List-UtilsBy-0.10/Makefile.PL 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/Makefile.PL 2018-02-01 00:21:27.000000000 +0100 @@ -1,4 +1,4 @@ -# Note: this file was auto-generated by Module::Build::Compat version 0.4211 +# Note: this file was auto-generated by Module::Build::Compat version 0.4220 use ExtUtils::MakeMaker; WriteMakefile ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/README new/List-UtilsBy-0.11/README --- old/List-UtilsBy-0.10/README 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/README 2018-02-01 00:21:27.000000000 +0100 @@ -1,165 +1,190 @@ NAME - `List::UtilsBy' - higher-order list utility functions -SYNOPSIS - use List::UtilsBy qw( nsort_by min_by ); + List::UtilsBy - higher-order list utility functions - use File::stat qw( stat ); - my @files_by_age = nsort_by { stat($_)->mtime } @files; +SYNOPSIS - my $shortest_name = min_by { length } @names; + use List::UtilsBy qw( nsort_by min_by ); + + use File::stat qw( stat ); + my @files_by_age = nsort_by { stat($_)->mtime } @files; + + my $shortest_name = min_by { length } @names; DESCRIPTION + This module provides a number of list utility functions, all of which take an initial code block to control their behaviour. They are - variations on similar core perl or `List::Util' functions of similar + variations on similar core perl or List::Util functions of similar names, but which use the block to control their behaviour. For example, - the core Perl function `sort' takes a list of values and returns them, - sorted into order by their string value. The `sort_by' function sorts + the core Perl function sort takes a list of values and returns them, + sorted into order by their string value. The "sort_by" function sorts them according to the string value returned by the extra function, when given each value. - my @names_sorted = sort @names; - - my @people_sorted = sort_by { $_->name } @people; + my @names_sorted = sort @names; + + my @people_sorted = sort_by { $_->name } @people; FUNCTIONS + All functions added since version 0.04 unless otherwise stated, as the original names for earlier versions were renamed. - sort_by + sort_by + @vals = sort_by { KEYFUNC } @vals Returns the list of values sorted according to the string values - returned by the `KEYFUNC' block or function. A typical use of this may - be to sort objects according to the string value of some accessor, such - as + returned by the KEYFUNC block or function. A typical use of this may be + to sort objects according to the string value of some accessor, such as - sort_by { $_->name } @people + sort_by { $_->name } @people - The key function is called in scalar context, being passed each value in - turn as both `$_' and the only argument in the parameters, `@_'. The + The key function is called in scalar context, being passed each value + in turn as both $_ and the only argument in the parameters, @_. The values are then sorted according to string comparisons on the values returned. This is equivalent to - sort { $a->name cmp $b->name } @people + sort { $a->name cmp $b->name } @people - except that it guarantees the `name' accessor will be executed only once + except that it guarantees the name accessor will be executed only once per value. One interesting use-case is to sort strings which may have numbers embedded in them "naturally", rather than lexically. - sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings + 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. - nsort_by + nsort_by + @vals = nsort_by { KEYFUNC } @vals - Similar to `sort_by' but compares its key values numerically. + Similar to "sort_by" but compares its key values numerically. - rev_sort_by - rev_nsort_by - @vals = rev_sort_by { KEYFUNC } @vals + rev_sort_by + + rev_nsort_by + @vals = rev_sort_by { KEYFUNC } @vals + @vals = rev_nsort_by { KEYFUNC } @vals - *Since version 0.06.* + Since version 0.06. - Similar to `sort_by' and `nsort_by' but returns the list in the reverse + Similar to "sort_by" and "nsort_by" but returns the list in the reverse order. Equivalent to - @vals = reverse sort_by { KEYFUNC } @vals + @vals = reverse sort_by { KEYFUNC } @vals except that these functions are slightly more efficient because they - avoid the final `reverse' operation. + avoid the final reverse operation. - max_by - $optimal = max_by { KEYFUNC } @vals + max_by + $optimal = max_by { KEYFUNC } @vals + @optimal = max_by { KEYFUNC } @vals - Returns the (first) value from `@vals' that gives the numerically - largest result from the key function. - - my $tallest = max_by { $_->height } @people - - use File::stat qw( stat ); - my $newest = max_by { stat($_)->mtime } @files; + Returns the (first) value from @vals that gives the numerically largest + result from the key function. - In scalar context, the first maximal value is returned. In list context, - a list of all the maximal values is returned. This may be used to obtain - positions other than the first, if order is significant. + my $tallest = max_by { $_->height } @people + + use File::stat qw( stat ); + my $newest = max_by { stat($_)->mtime } @files; + + In scalar context, the first maximal value is returned. In list + context, a 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 `nsort_by' function, this is also provided under - the name `nmax_by' since it behaves numerically. + For symmetry with the "nsort_by" function, this is also provided under + the name nmax_by since it behaves numerically. - min_by - $optimal = min_by { KEYFUNC } @vals + min_by + $optimal = min_by { KEYFUNC } @vals + @optimal = min_by { KEYFUNC } @vals - Similar to `max_by' but returns values which give the numerically - smallest result from the key function. Also provided as `nmin_by' + Similar to "max_by" but returns values which give the numerically + smallest result from the key function. Also provided as nmin_by + + minmax_by + + ( $minimal, $maximal ) = minmax_by { KEYFUNC } @vals + + Since version 0.11. + + Similar to calling both "min_by" and "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 nminmax_by. + + uniq_by - uniq_by @vals = uniq_by { KEYFUNC } @vals Returns a list of the subset of values for which the key function block returns unique values. The first value yielding a particular key is chosen, subsequent values are rejected. - my @some_fruit = uniq_by { $_->colour } @fruit; + my @some_fruit = uniq_by { $_->colour } @fruit; - To select instead the last value per key, reverse the input list. If the - order of the results is significant, don't forget to reverse the result - as well: + To select instead the last value per key, reverse the input list. If + the order of the results is significant, don't forget to reverse the + result as well: - my @some_fruit = reverse uniq_by { $_->colour } reverse @fruit; + 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). + (such as numbers, or object references which overload stringification + in a suitable manner). + + partition_by - partition_by %parts = partition_by { KEYFUNC } @vals Returns a key/value list of ARRAY refs containing all the original values distributed according to the result of the key function block. - Each value will be an ARRAY ref containing all the values which returned - the string from the key function, in their original order. + Each value will be an ARRAY ref containing all the values which + returned the string from the key function, in their original order. - my %balls_by_colour = partition_by { $_->colour } @balls; + 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). + (such as numbers, or object references which overload stringification + in a suitable manner). + + count_by - count_by %counts = count_by { KEYFUNC } @vals - *Since version 0.07.* + Since version 0.07. - Returns a key/value list of integers, giving the number of times the key - function block returned the key, for each value in the list. + Returns a key/value list of integers, giving the number of times the + key function block returned the key, for each value in the list. - my %count_of_balls = count_by { $_->colour } @balls; + 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). + (such as numbers, or object references which overload stringification + in a suitable manner). + + zip_by - zip_by @vals = zip_by { ITEMFUNC } \@arr0, \@arr1, \@arr2,... Returns a list of each of the values returned by the function block, @@ -168,146 +193,167 @@ function having been invoked with arguments at that position, from across each of the arrays given. - my @transposition = zip_by { [ @_ ] } @matrix; - - my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames; - - print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ]; + my @transposition = zip_by { [ @_ ] } @matrix; + + my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames; + + print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ]; If some of the arrays are shorter than others, the function will behave - as if they had `undef' in the trailing positions. The following two - lines are equivalent: + as if they had undef in the trailing positions. The following two lines + are equivalent: - zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ] - f( 1, "a" ), f( 2, "b" ), f( 3, undef ) + zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ] + f( 1, "a" ), f( 2, "b" ), f( 3, undef ) - The item function is called by `map', so if it returns a list, the - entire list is included in the result. This can be useful for example, - for generating a hash from two separate lists of keys and values + The item function is called by map, so if it returns a list, the entire + list is included in the result. This can be useful for example, for + generating 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 ) + 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 `zipWith', e.g. in + (A function having this behaviour is sometimes called zipWith, e.g. in Haskell, but that name would not fit the naming scheme used by this module). - unzip_by + unzip_by + $arr0, $arr1, $arr2, ... = unzip_by { ITEMFUNC } @vals - *Since version 0.09.* + Since version 0.09. - Returns a list of ARRAY references containing the values returned by the - function block, when invoked for each of the values given in the input - list. Each of the returned ARRAY references will contain the values - returned at that corresponding position by the function block. That is, - the first returned ARRAY reference will contain all the values returned - in the first position by the function block, the second will contain all - the values from the second position, and so on. + Returns a list of ARRAY references containing the values returned by + the function block, when invoked for each of the values given in the + input list. Each of the returned ARRAY references will contain the + values returned at that corresponding position by the function block. + That is, the first returned ARRAY reference will contain all the values + returned in the first position by the function block, the second will + contain all the values from the second position, and so on. - my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names; + my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names; If the function returns lists of differing lengths, the result will be - padded with `undef' in the missing elements. + padded with undef in the missing elements. - This function is an inverse of `zip_by', if given a corresponding + This function is an inverse of "zip_by", if given a corresponding inverse function. - extract_by + extract_by + @vals = extract_by { SELECTFUNC } @arr - *Since version 0.05.* + Since version 0.05. Removes elements from the referenced array on which the selection function returns true, and returns a list containing those elements. - This function is similar to `grep', except that it modifies the - referenced array to remove the selected values from it, leaving only the - unselected ones. - - my @red_balls = extract_by { $_->color eq "red" } @balls; - - # Now there are no red balls in the @balls array + This function is similar to grep, except that it modifies the + referenced array to remove the selected values from it, leaving only + the unselected ones. + + my @red_balls = extract_by { $_->color eq "red" } @balls; + + # Now there are no red balls in the @balls array This function modifies a real array, unlike most of the other functions in this module. Because of this, it requires a real array, not just a list. - This function is implemented by invoking `splice()' on the array, not by + This function is implemented by invoking splice on the array, not by constructing a new list and assigning it. One result of this is that weak references will not be disturbed. - extract_by { !defined $_ } @refs; + extract_by { !defined $_ } @refs; - will leave weak references weakened in the `@refs' array, whereas + will leave weak references weakened in the @refs array, whereas - @refs = grep { defined $_ } @refs; + @refs = grep { defined $_ } @refs; will strengthen them all again. - extract_first_by + extract_first_by + $val = extract_first_by { SELECTFUNC } @arr - *Since version 0.10.* + Since version 0.10. - A hybrid between `extract_by' and `List::Util::first'. Removes the first + A hybrid between "extract_by" and List::Util::first. Removes the first element from the referenced array on which the selection function returns true, returning it. - As with `extract_by', this function requires a real array and not just a - list, and is also implemented using `splice()' so that weak references + As with "extract_by", this function requires a real array and not just + a list, and is also implemented using 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 - `undef'. + empty list in list context. This allows a caller to distinguish the + case between no matching element, and the first matching element being + undef. + + weighted_shuffle_by - weighted_shuffle_by @vals = weighted_shuffle_by { WEIGHTFUNC } @vals - *Since version 0.07.* + 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 - `WEIGHTFUNC'. The probabilty of each item being returned first will be + WEIGHTFUNC. The probabilty of each item being returned first will be distributed with the distribution of the weights, and so on recursively for the remaining items. - bundle_by + bundle_by + @vals = bundle_by { BLOCKFUNC } $number, @vals - *Since version 0.07.* + Since version 0.07. - Similar to a regular `map' functional, returns a list of the values - returned by `BLOCKFUNC'. Values from the input list are given to the - block function in bundles of `$number'. + Similar to a regular map functional, returns a list of the values + returned by BLOCKFUNC. Values from the input list are given to the + block function in bundles of $number. If given a list of values whose length does not evenly divide by - `$number', the final call will be passed fewer elements than the others. + $number, the final call will be passed fewer elements than the others. TODO - * XS implementations - These functions are currently all written in pure perl. Some at - least, may benefit from having XS implementations to speed up their - logic. - - * Merge into List::Util or List::MoreUtils - This module shouldn't really exist. The functions should instead be - part of one of the existing modules that already contain many list - utility functions. Having Yet Another List Utilty Module just - worsens the problem. - - I have attempted to contact the authors of both of the above - modules, to no avail; therefore I decided it best to write and - release this code here anyway so that it is at least on CPAN. Once - there, we can then see how best to merge it into an existing module. - - *Updated 2015/07/16*: As I am now the maintainer of List::Util, some - amount of merging/copying should be possible. However, given the - latter's key position in the core perl distribution and head of the - "CPAN River" I am keen not to do this wholesale, but a selected pick - of what seems best, by a popular consensus. + + * XS implementations + + These functions are currently all written in pure perl. Some at + least, may benefit from having XS implementations to speed up their + logic. + + * Merge into List::Util or List::MoreUtils + + This module shouldn't really exist. The functions should instead be + part of one of the existing modules that already contain many list + utility functions. Having Yet Another List Utilty Module just worsens + the problem. + + I have attempted to contact the authors of both of the above modules, + to no avail; therefore I decided it best to write and release this + code here anyway so that it is at least on CPAN. Once there, we can + then see how best to merge it into an existing module. + + Updated 2015/07/16: As I am now the maintainer of List::Util, some + amount of merging/copying should be possible. However, given the + latter's key position in the core perl distribution and head of the + "CPAN River" I am keen not to do this wholesale, but a selected pick + of what seems best, by a popular consensus. + + * head and tail-like functions + + Consider perhaps + + head_before { COND } LIST # excludes terminating element + head_upto { COND } LIST # includes terminating element + + tail_since { COND } LIST # includes initiating element + tail_after { COND } LIST # excludes initiating element + + (See also https://rt.cpan.org/Ticket/Display.html?id=105907). AUTHOR + Paul Evans <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/lib/List/UtilsBy.pm new/List-UtilsBy-0.11/lib/List/UtilsBy.pm --- old/List-UtilsBy-0.10/lib/List/UtilsBy.pm 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/lib/List/UtilsBy.pm 2018-02-01 00:21:27.000000000 +0100 @@ -1,14 +1,14 @@ # You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # -# (C) Paul Evans, 2009-2015 -- [email protected] +# (C) Paul Evans, 2009-2018 -- [email protected] package List::UtilsBy; use strict; use warnings; -our $VERSION = '0.10'; +our $VERSION = '0.11'; use Exporter 'import'; @@ -20,6 +20,7 @@ max_by nmax_by min_by nmin_by + minmax_by nminmax_by uniq_by @@ -43,12 +44,12 @@ =head1 SYNOPSIS - use List::UtilsBy qw( nsort_by min_by ); + use List::UtilsBy qw( nsort_by min_by ); - use File::stat qw( stat ); - my @files_by_age = nsort_by { stat($_)->mtime } @files; + use File::stat qw( stat ); + my @files_by_age = nsort_by { stat($_)->mtime } @files; - my $shortest_name = min_by { length } @names; + my $shortest_name = min_by { length } @names; =head1 DESCRIPTION @@ -57,12 +58,12 @@ core perl or C<List::Util> functions of similar names, but which use the block to control their behaviour. For example, the core Perl function C<sort> takes a list of values and returns them, sorted into order by their string value. -The C<sort_by> function sorts them according to the string value returned by +The L</sort_by> function sorts them according to the string value returned by the extra function, when given each value. - my @names_sorted = sort @names; + my @names_sorted = sort @names; - my @people_sorted = sort_by { $_->name } @people; + my @people_sorted = sort_by { $_->name } @people; =cut @@ -81,7 +82,7 @@ the C<KEYFUNC> block or function. A typical use of this may be to sort objects according to the string value of some accessor, such as - sort_by { $_->name } @people + sort_by { $_->name } @people The key function is called in scalar context, being passed each value in turn as both C<$_> and the only argument in the parameters, C<@_>. The values are @@ -89,7 +90,7 @@ This is equivalent to - sort { $a->name cmp $b->name } @people + sort { $a->name cmp $b->name } @people except that it guarantees the C<name> accessor will be executed only once per value. @@ -97,7 +98,7 @@ One interesting use-case is to sort strings which may have numbers embedded in them "naturally", rather than lexically. - sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings + 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 @@ -117,7 +118,7 @@ @vals = nsort_by { KEYFUNC } @vals -Similar to C<sort_by> but compares its key values numerically. +Similar to L</sort_by> but compares its key values numerically. =cut @@ -139,10 +140,10 @@ I<Since version 0.06.> -Similar to C<sort_by> and C<nsort_by> but returns the list in the reverse +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 + @vals = reverse sort_by { KEYFUNC } @vals except that these functions are slightly more efficient because they avoid the final C<reverse> operation. @@ -174,10 +175,10 @@ Returns the (first) value from C<@vals> that gives the numerically largest result from the key function. - my $tallest = max_by { $_->height } @people + my $tallest = max_by { $_->height } @people - use File::stat qw( stat ); - my $newest = max_by { stat($_)->mtime } @files; + use File::stat qw( stat ); + my $newest = max_by { stat($_)->mtime } @files; In scalar context, the first maximal value is returned. In list context, a list of all the maximal values is returned. This may be used to obtain @@ -185,7 +186,7 @@ If called on an empty list, an empty list is returned. -For symmetry with the C<nsort_by> function, this is also provided under the +For symmetry with the L</nsort_by> function, this is also provided under the name C<nmax_by> since it behaves numerically. =cut @@ -223,7 +224,7 @@ @optimal = min_by { KEYFUNC } @vals -Similar to C<max_by> but returns values which give the numerically smallest +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 @@ -255,6 +256,72 @@ *nmin_by = \&min_by; +=head2 minmax_by + + ( $minimal, $maximal ) = minmax_by { KEYFUNC } @vals + +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 @_; + + my $maximal = $_ = shift @_; + my $max = $code->( $_ ); + + if( $max < $min ) { + ( $maximal, $minimal ) = ( $minimal, $maximal ); + ( $max, $min ) = ( $min, $max ); + } + + # Minmax algorithm is faster than naïve min + max individually because it + # takes pairs of values + while( @_ ) { + my $try_minimal = $_ = shift @_; + my $try_min = $code->( $_ ); + + my $try_maximal = $try_minimal; + my $try_max = $try_min; + if( @_ ) { + $try_maximal = $_ = shift @_; + $try_max = $code->( $_ ); + + if( $try_max < $try_min ) { + ( $try_minimal, $try_maximal ) = ( $try_maximal, $try_minimal ); + ( $try_min, $try_max ) = ( $try_max, $try_min ); + } + } + + if( $try_min < $min ) { + $minimal = $try_minimal; + $min = $try_min; + } + if( $try_max > $max ) { + $maximal = $try_maximal; + $max = $try_max; + } + } + + return ( $minimal, $maximal ); +} + +*nminmax_by = \&minmax_by; + =head2 uniq_by @vals = uniq_by { KEYFUNC } @vals @@ -263,12 +330,12 @@ returns unique values. The first value yielding a particular key is chosen, subsequent values are rejected. - my @some_fruit = uniq_by { $_->colour } @fruit; + my @some_fruit = uniq_by { $_->colour } @fruit; To select instead the last value per key, reverse the input list. If the order of the results is significant, don't forget to reverse the result as well: - my @some_fruit = reverse uniq_by { $_->colour } reverse @fruit; + 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 @@ -297,7 +364,7 @@ be an ARRAY ref containing all the values which returned the string from the key function, in their original order. - my %balls_by_colour = partition_by { $_->colour } @balls; + 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 @@ -325,7 +392,7 @@ Returns a key/value list of integers, giving the number of times the key function block returned the key, for each value in the list. - my %count_of_balls = count_by { $_->colour } @balls; + 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 @@ -353,25 +420,25 @@ value in the returned list will be the result of the function having been invoked with arguments at that position, from across each of the arrays given. - my @transposition = zip_by { [ @_ ] } @matrix; + my @transposition = zip_by { [ @_ ] } @matrix; - my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames; + my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames; - print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ]; + print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ]; If some of the arrays are shorter than others, the function will behave as if they had C<undef> in the trailing positions. The following two lines are equivalent: - zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ] - f( 1, "a" ), f( 2, "b" ), f( 3, undef ) + zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ] + f( 1, "a" ), f( 2, "b" ), f( 3, undef ) The item function is called by C<map>, so if it returns a list, the entire list is included in the result. This can be useful for example, for generating 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 ) + 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). @@ -407,12 +474,12 @@ the function block, the second will contain all the values from the second position, and so on. - my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names; + 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 C<zip_by>, if given a corresponding inverse +This function is an inverse of L</zip_by>, if given a corresponding inverse function. =cut @@ -442,22 +509,22 @@ similar to C<grep>, except that it modifies the referenced array to remove the selected values from it, leaving only the unselected ones. - my @red_balls = extract_by { $_->color eq "red" } @balls; + my @red_balls = extract_by { $_->color eq "red" } @balls; - # Now there are no red balls in the @balls array + # Now there are no red balls in the @balls array This function modifies a real array, unlike most of the other functions in this module. Because of this, it requires a real array, not just a list. -This function is implemented by invoking C<splice()> on the array, not by +This function is implemented by invoking C<splice> on the array, not by constructing a new list and assigning it. One result of this is that weak references will not be disturbed. - extract_by { !defined $_ } @refs; + extract_by { !defined $_ } @refs; will leave weak references weakened in the C<@refs> array, whereas - @refs = grep { defined $_ } @refs; + @refs = grep { defined $_ } @refs; will strengthen them all again. @@ -486,12 +553,12 @@ I<Since version 0.10.> -A hybrid between C<extract_by> and C<List::Util::first>. Removes the first +A hybrid between L</extract_by> and C<List::Util::first>. Removes the first element from the referenced array on which the selection function returns true, returning it. -As with C<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 +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 @@ -606,6 +673,18 @@ keen not to do this wholesale, but a selected pick of what seems best, by a popular consensus. +=item * C<head> and C<tail>-like functions + +Consider perhaps + + head_before { COND } LIST # excludes terminating element + head_upto { COND } LIST # includes terminating element + + tail_since { COND } LIST # includes initiating element + tail_after { COND } LIST # excludes initiating element + +(See also L<https://rt.cpan.org/Ticket/Display.html?id=105907>). + =back =head1 AUTHOR diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/t/03max_by.t new/List-UtilsBy-0.11/t/03max_by.t --- old/List-UtilsBy-0.10/t/03max_by.t 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/t/03max_by.t 1970-01-01 01:00:00.000000000 +0100 @@ -1,25 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Test::More; - -use List::UtilsBy qw( max_by nmax_by ); - -is_deeply( [ max_by {} ], [], 'empty list yields empty' ); - -is_deeply( ( scalar max_by { $_ } 10 ), 10, 'unit list yields value in scalar context' ); -is_deeply( [ max_by { $_ } 10 ], [ 10 ], 'unit list yields unit list value' ); - -is_deeply( ( scalar max_by { $_ } 10, 20 ), 20, 'identity function on $_' ); -is_deeply( ( scalar max_by { $_[0] } 10, 20 ), 20, 'identity function on $_[0]' ); - -is_deeply( ( scalar max_by { length $_ } "a", "ccc", "bb" ), "ccc", 'length function' ); - -is_deeply( ( scalar max_by { length $_ } "a", "ccc", "bb", "ddd" ), "ccc", 'ties yield first in scalar context' ); -is_deeply( [ max_by { length $_ } "a", "ccc", "bb", "ddd" ], [ "ccc", "ddd" ], 'ties yield all maximal in list context' ); - -is_deeply( ( scalar nmax_by { $_ } 10, 20 ), 20, 'nmax_by alias' ); - -done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/t/03max_min_by.t new/List-UtilsBy-0.11/t/03max_min_by.t --- old/List-UtilsBy-0.10/t/03max_min_by.t 1970-01-01 01:00:00.000000000 +0100 +++ new/List-UtilsBy-0.11/t/03max_min_by.t 2018-02-01 00:21:27.000000000 +0100 @@ -0,0 +1,66 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More; + +use List::UtilsBy qw( + max_by nmax_by + min_by nmin_by + minmax_by nminmax_by +); + +# max_by +{ + is_deeply( [ max_by {} ], [], 'empty list yields empty' ); + + is_deeply( ( scalar max_by { $_ } 10 ), 10, 'unit list yields value in scalar context' ); + is_deeply( [ max_by { $_ } 10 ], [ 10 ], 'unit list yields unit list value' ); + + is_deeply( ( scalar max_by { $_ } 10, 20 ), 20, 'identity function on $_' ); + is_deeply( ( scalar max_by { $_[0] } 10, 20 ), 20, 'identity function on $_[0]' ); + + is_deeply( ( scalar max_by { length $_ } "a", "ccc", "bb" ), "ccc", 'length function' ); + + is_deeply( ( scalar max_by { length $_ } "a", "ccc", "bb", "ddd" ), "ccc", 'ties yield first in scalar context' ); + is_deeply( [ max_by { length $_ } "a", "ccc", "bb", "ddd" ], [ "ccc", "ddd" ], 'ties yield all maximal in list context' ); + + is_deeply( ( scalar nmax_by { $_ } 10, 20 ), 20, 'nmax_by alias' ); +} + +# min_by +{ + is_deeply( [ min_by {} ], [], 'empty list yields empty' ); + + is_deeply( ( scalar min_by { $_ } 10 ), 10, 'unit list yields value in scalar context' ); + is_deeply( [ min_by { $_ } 10 ], [ 10 ], 'unit list yields unit list value' ); + + is_deeply( ( scalar min_by { $_ } 10, 20 ), 10, 'identity function on $_' ); + is_deeply( ( scalar min_by { $_[0] } 10, 20 ), 10, 'identity function on $_[0]' ); + + is_deeply( ( scalar min_by { length $_ } "a", "ccc", "bb" ), "a", 'length function' ); + + is_deeply( ( scalar min_by { length $_ } "a", "ccc", "bb", "e" ), "a", 'ties yield first in scalar context' ); + is_deeply( [ min_by { length $_ } "a", "ccc", "bb", "ddd", "e" ], [ "a", "e" ], 'ties yield all minimal in list context' ); + + is_deeply( ( scalar nmin_by { $_ } 10, 20 ), 10, 'nmin_by alias' ); +} + +# minmax_by +{ + is_deeply( [ minmax_by {} ], [], 'empty list yields empty' ); + + is_deeply( [ minmax_by { $_ } 10 ], [ 10, 10, ], 'unit list yields value twice' ); + + is_deeply( [ minmax_by { $_ } 10, 20, 30, 40, 50 ], [ 10, 50 ], 'identity function on $_' ); + is_deeply( [ minmax_by { $_[0] } 10, 20, 30, 40, 50 ], [ 10, 50 ], 'identity function on $_[0]' ); + + is_deeply( [ minmax_by { $_ } 50, 40, 30, 20, 10 ], [ 10, 50 ], 'identity function on reversed input' ); + + is_deeply( [ minmax_by { length $_ } "a", "ccc", "bb" ], [ "a", "ccc" ], 'length function' ); + + is_deeply( [ nminmax_by { $_ } 10 ], [ 10, 10, ], 'nminmax_by alias' ); +} + +done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/t/04min_by.t new/List-UtilsBy-0.11/t/04min_by.t --- old/List-UtilsBy-0.10/t/04min_by.t 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/t/04min_by.t 1970-01-01 01:00:00.000000000 +0100 @@ -1,25 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Test::More; - -use List::UtilsBy qw( min_by nmin_by ); - -is_deeply( [ min_by {} ], [], 'empty list yields empty' ); - -is_deeply( ( scalar min_by { $_ } 10 ), 10, 'unit list yields value in scalar context' ); -is_deeply( [ min_by { $_ } 10 ], [ 10 ], 'unit list yields unit list value' ); - -is_deeply( ( scalar min_by { $_ } 10, 20 ), 10, 'identity function on $_' ); -is_deeply( ( scalar min_by { $_[0] } 10, 20 ), 10, 'identity function on $_[0]' ); - -is_deeply( ( scalar min_by { length $_ } "a", "ccc", "bb" ), "a", 'length function' ); - -is_deeply( ( scalar min_by { length $_ } "a", "ccc", "bb", "e" ), "a", 'ties yield first in scalar context' ); -is_deeply( [ min_by { length $_ } "a", "ccc", "bb", "ddd", "e" ], [ "a", "e" ], 'ties yield all minimal in list context' ); - -is_deeply( ( scalar nmin_by { $_ } 10, 20 ), 10, 'nmin_by alias' ); - -done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/List-UtilsBy-0.10/t/11weighted_shuffle_by.t new/List-UtilsBy-0.11/t/11weighted_shuffle_by.t --- old/List-UtilsBy-0.10/t/11weighted_shuffle_by.t 2015-07-16 20:23:58.000000000 +0200 +++ new/List-UtilsBy-0.11/t/11weighted_shuffle_by.t 2018-02-01 00:21:27.000000000 +0100 @@ -4,6 +4,8 @@ use warnings; use Test::More; + +use lib "."; use t::Unrandom; use List::UtilsBy qw( weighted_shuffle_by );
