Modul List::UtilsBy in Abhängigkeiten und als Fallback aufgenommen
[kivitendo-erp.git] / modules / fallback / List / UtilsBy.pm
1 #  You may distribute under the terms of either the GNU General Public License
2 #  or the Artistic License (the same terms as Perl itself)
3 #
4 #  (C) Paul Evans, 2009-2012 -- leonerd@leonerd.org.uk
5
6 package List::UtilsBy;
7
8 use strict;
9 use warnings;
10
11 our $VERSION = '0.09';
12
13 use Exporter 'import';
14
15 our @EXPORT_OK = qw(
16    sort_by
17    nsort_by
18    rev_sort_by
19    rev_nsort_by
20
21    max_by nmax_by
22    min_by nmin_by
23
24    uniq_by
25
26    partition_by
27    count_by
28
29    zip_by
30    unzip_by
31
32    extract_by
33
34    weighted_shuffle_by
35
36    bundle_by
37 );
38
39 =head1 NAME
40
41 C<List::UtilsBy> - higher-order list utility functions
42
43 =head1 SYNOPSIS
44
45  use List::UtilsBy qw( nsort_by min_by );
46
47  use File::stat qw( stat );
48  my @files_by_age = nsort_by { stat($_)->mtime } @files;
49
50  my $shortest_name = min_by { length } @names;
51
52 =head1 DESCRIPTION
53
54 This module provides a number of list utility functions, all of which take an
55 initial code block to control their behaviour. They are variations on similar
56 core perl or C<List::Util> functions of similar names, but which use the block
57 to control their behaviour. For example, the core Perl function C<sort> takes
58 a list of values and returns them, sorted into order by their string value.
59 The C<sort_by> function sorts them according to the string value returned by
60 the extra function, when given each value.
61
62  my @names_sorted = sort @names;
63
64  my @people_sorted = sort_by { $_->name } @people;
65
66 =cut
67
68 =head1 FUNCTIONS
69
70 =cut
71
72 =head2 @vals = sort_by { KEYFUNC } @vals
73
74 Returns the list of values sorted according to the string values returned by
75 the C<KEYFUNC> block or function. A typical use of this may be to sort objects
76 according to the string value of some accessor, such as
77
78  sort_by { $_->name } @people
79
80 The key function is called in scalar context, being passed each value in turn
81 as both C<$_> and the only argument in the parameters, C<@_>. The values are
82 then sorted according to string comparisons on the values returned.
83
84 This is equivalent to
85
86  sort { $a->name cmp $b->name } @people
87
88 except that it guarantees the C<name> accessor will be executed only once per
89 value.
90
91 One interesting use-case is to sort strings which may have numbers embedded in
92 them "naturally", rather than lexically.
93
94  sort_by { s/(\d+)/sprintf "%09d", $1/eg; $_ } @strings
95
96 This sorts strings by generating sort keys which zero-pad the embedded numbers
97 to some level (9 digits in this case), helping to ensure the lexical sort puts
98 them in the correct order.
99
100 =cut
101
102 sub sort_by(&@)
103 {
104    my $keygen = shift;
105
106    my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
107    return @_[ sort { $keys[$a] cmp $keys[$b] } 0 .. $#_ ];
108 }
109
110 =head2 @vals = nsort_by { KEYFUNC } @vals
111
112 Similar to C<sort_by> but compares its key values numerically.
113
114 =cut
115
116 sub nsort_by(&@)
117 {
118    my $keygen = shift;
119
120    my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
121    return @_[ sort { $keys[$a] <=> $keys[$b] } 0 .. $#_ ];
122 }
123
124 =head2 @vals = rev_sort_by { KEYFUNC } @vals
125
126 =head2 @vals = rev_nsort_by { KEYFUNC } @vals
127
128 Similar to C<sort_by> and C<nsort_by> but returns the list in the reverse
129 order. Equivalent to
130
131  @vals = reverse sort_by { KEYFUNC } @vals
132
133 except that these functions are slightly more efficient because they avoid
134 the final C<reverse> operation.
135
136 =cut
137
138 sub rev_sort_by(&@)
139 {
140    my $keygen = shift;
141
142    my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
143    return @_[ sort { $keys[$b] cmp $keys[$a] } 0 .. $#_ ];
144 }
145
146 sub rev_nsort_by(&@)
147 {
148    my $keygen = shift;
149
150    my @keys = map { local $_ = $_; scalar $keygen->( $_ ) } @_;
151    return @_[ sort { $keys[$b] <=> $keys[$a] } 0 .. $#_ ];
152 }
153
154 =head2 $optimal = max_by { KEYFUNC } @vals
155
156 =head2 @optimal = max_by { KEYFUNC } @vals
157
158 Returns the (first) value from C<@vals> that gives the numerically largest
159 result from the key function.
160
161  my $tallest = max_by { $_->height } @people
162
163  use File::stat qw( stat );
164  my $newest = max_by { stat($_)->mtime } @files;
165
166 In scalar context, the first maximal value is returned. In list context, a
167 list of all the maximal values is returned. This may be used to obtain
168 positions other than the first, if order is significant.
169
170 If called on an empty list, an empty list is returned.
171
172 For symmetry with the C<nsort_by> function, this is also provided under the
173 name C<nmax_by> since it behaves numerically.
174
175 =cut
176
177 sub max_by(&@)
178 {
179    my $code = shift;
180
181    return unless @_;
182
183    local $_;
184
185    my @maximal = $_ = shift @_;
186    my $max     = $code->( $_ );
187
188    foreach ( @_ ) {
189       my $this = $code->( $_ );
190       if( $this > $max ) {
191          @maximal = $_;
192          $max     = $this;
193       }
194       elsif( wantarray and $this == $max ) {
195          push @maximal, $_;
196       }
197    }
198
199    return wantarray ? @maximal : $maximal[0];
200 }
201
202 *nmax_by = \&max_by;
203
204 =head2 $optimal = min_by { KEYFUNC } @vals
205
206 =head2 @optimal = min_by { KEYFUNC } @vals
207
208 Similar to C<max_by> but returns values which give the numerically smallest
209 result from the key function. Also provided as C<nmin_by>
210
211 =cut
212
213 sub min_by(&@)
214 {
215    my $code = shift;
216
217    return unless @_;
218
219    local $_;
220
221    my @minimal = $_ = shift @_;
222    my $min     = $code->( $_ );
223
224    foreach ( @_ ) {
225       my $this = $code->( $_ );
226       if( $this < $min ) {
227          @minimal = $_;
228          $min     = $this;
229       }
230       elsif( wantarray and $this == $min ) {
231          push @minimal, $_;
232       }
233    }
234
235    return wantarray ? @minimal : $minimal[0];
236 }
237
238 *nmin_by = \&min_by;
239
240 =head2 @vals = uniq_by { KEYFUNC } @vals
241
242 Returns a list of the subset of values for which the key function block
243 returns unique values. The first value yielding a particular key is chosen,
244 subsequent values are rejected.
245
246  my @some_fruit = uniq_by { $_->colour } @fruit;
247
248 To select instead the last value per key, reverse the input list. If the order
249 of the results is significant, don't forget to reverse the result as well:
250
251  my @some_fruit = reverse uniq_by { $_->colour } reverse @fruit;
252
253 =cut
254
255 sub uniq_by(&@)
256 {
257    my $code = shift;
258
259    my %present;
260    return grep {
261       my $key = $code->( local $_ = $_ );
262       !$present{$key}++
263    } @_;
264 }
265
266 =head2 %parts = partition_by { KEYFUNC } @vals
267
268 Returns a key/value list of ARRAY refs containing all the original values
269 distributed according to the result of the key function block. Each value will
270 be an ARRAY ref containing all the values which returned the string from the
271 key function, in their original order.
272
273  my %balls_by_colour = partition_by { $_->colour } @balls;
274
275 Because the values returned by the key function are used as hash keys, they
276 ought to either be strings, or at least well-behaved as strings (such as
277 numbers, or object references which overload stringification in a suitable
278 manner).
279
280 =cut
281
282 sub partition_by(&@)
283 {
284    my $code = shift;
285
286    my %parts;
287    push @{ $parts{ $code->( local $_ = $_ ) } }, $_ for @_;
288
289    return %parts;
290 }
291
292 =head2 %counts = count_by { KEYFUNC } @vals
293
294 Returns a key/value list of integers, giving the number of times the key
295 function block returned the key, for each value in the list.
296
297  my %count_of_balls = count_by { $_->colour } @balls;
298
299 Because the values returned by the key function are used as hash keys, they
300 ought to either be strings, or at least well-behaved as strings (such as
301 numbers, or object references which overload stringification in a suitable
302 manner).
303
304 =cut
305
306 sub count_by(&@)
307 {
308    my $code = shift;
309
310    my %counts;
311    $counts{ $code->( local $_ = $_ ) }++ for @_;
312
313    return %counts;
314 }
315
316 =head2 @vals = zip_by { ITEMFUNC } \@arr0, \@arr1, \@arr2,...
317
318 Returns a list of each of the values returned by the function block, when
319 invoked with values from across each each of the given ARRAY references. Each
320 value in the returned list will be the result of the function having been
321 invoked with arguments at that position, from across each of the arrays given.
322
323  my @transposition = zip_by { [ @_ ] } @matrix;
324
325  my @names = zip_by { "$_[1], $_[0]" } \@firstnames, \@surnames;
326
327  print zip_by { "$_[0] => $_[1]\n" } [ keys %hash ], [ values %hash ];
328
329 If some of the arrays are shorter than others, the function will behave as if
330 they had C<undef> in the trailing positions. The following two lines are
331 equivalent:
332
333  zip_by { f(@_) } [ 1, 2, 3 ], [ "a", "b" ]
334  f( 1, "a" ), f( 2, "b" ), f( 3, undef )
335
336 The item function is called by C<map>, so if it returns a list, the entire
337 list is included in the result. This can be useful for example, for generating
338 a hash from two separate lists of keys and values
339
340  my %nums = zip_by { @_ } [qw( one two three )], [ 1, 2, 3 ];
341  # %nums = ( one => 1, two => 2, three => 3 )
342
343 (A function having this behaviour is sometimes called C<zipWith>, e.g. in
344 Haskell, but that name would not fit the naming scheme used by this module).
345
346 =cut
347
348 sub zip_by(&@)
349 {
350    my $code = shift;
351
352    @_ or return;
353
354    my $len = 0;
355    scalar @$_ > $len and $len = scalar @$_ for @_;
356
357    return map {
358       my $idx = $_;
359       $code->( map { $_[$_][$idx] } 0 .. $#_ )
360    } 0 .. $len-1;
361 }
362
363 =head2 $arr0, $arr1, $arr2, ... = unzip_by { ITEMFUNC } @vals
364
365 Returns a list of ARRAY references containing the values returned by the
366 function block, when invoked for each of the values given in the input list.
367 Each of the returned ARRAY references will contain the values returned at that
368 corresponding position by the function block. That is, the first returned
369 ARRAY reference will contain all the values returned in the first position by
370 the function block, the second will contain all the values from the second
371 position, and so on.
372
373  my ( $firstnames, $lastnames ) = unzip_by { m/^(.*?) (.*)$/ } @names;
374
375 If the function returns lists of differing lengths, the result will be padded
376 with C<undef> in the missing elements.
377
378 This function is an inverse of C<zip_by>, if given a corresponding inverse
379 function.
380
381 =cut
382
383 sub unzip_by(&@)
384 {
385    my $code = shift;
386
387    my @ret;
388    foreach my $idx ( 0 .. $#_ ) {
389       my @slice = $code->( local $_ = $_[$idx] );
390       $#slice = $#ret if @slice < @ret;
391       $ret[$_][$idx] = $slice[$_] for 0 .. $#slice;
392    }
393
394    return @ret;
395 }
396
397 =head2 @vals = extract_by { SELECTFUNC } @arr
398
399 Removes elements from the referenced array on which the selection function
400 returns true, and returns a list containing those elements. This function is
401 similar to C<grep>, except that it modifies the referenced array to remove the
402 selected values from it, leaving only the unselected ones.
403
404  my @red_balls = extract_by { $_->color eq "red" } @balls;
405
406  # Now there are no red balls in the @balls array
407
408 This function modifies a real array, unlike most of the other functions in this
409 module. Because of this, it requires a real array, not just a list.
410
411 This function is implemented by invoking C<splice()> on the array, not by
412 constructing a new list and assigning it. One result of this is that weak
413 references will not be disturbed.
414
415  extract_by { !defined $_ } @refs;
416
417 will leave weak references weakened in the C<@refs> array, whereas
418
419  @refs = grep { defined $_ } @refs;
420
421 will strengthen them all again.
422
423 =cut
424
425 sub extract_by(&\@)
426 {
427    my $code = shift;
428    my ( $arrref ) = @_;
429
430    my @ret;
431    for( my $idx = 0; $idx < scalar @$arrref; ) {
432       if( $code->( local $_ = $arrref->[$idx] ) ) {
433          push @ret, splice @$arrref, $idx, 1, ();
434       }
435       else {
436          $idx++;
437       }
438    }
439
440    return @ret;
441 }
442
443 =head2 @vals = weighted_shuffle_by { WEIGHTFUNC } @vals
444
445 Returns the list of values shuffled into a random order. The randomisation is
446 not uniform, but weighted by the value returned by the C<WEIGHTFUNC>. The
447 probabilty of each item being returned first will be distributed with the
448 distribution of the weights, and so on recursively for the remaining items.
449
450 =cut
451
452 sub weighted_shuffle_by(&@)
453 {
454    my $code = shift;
455    my @vals = @_;
456
457    my @weights = map { $code->( local $_ = $_ ) } @vals;
458
459    my @ret;
460    while( @vals > 1 ) {
461       my $total = 0; $total += $_ for @weights;
462       my $select = int rand $total;
463       my $idx = 0;
464       while( $select >= $weights[$idx] ) {
465          $select -= $weights[$idx++];
466       }
467
468       push @ret, splice @vals, $idx, 1, ();
469       splice @weights, $idx, 1, ();
470    }
471
472    push @ret, @vals if @vals;
473
474    return @ret;
475 }
476
477 =head2 @vals = bundle_by { BLOCKFUNC } $number, @vals
478
479 Similar to a regular C<map> functional, returns a list of the values returned
480 by C<BLOCKFUNC>. Values from the input list are given to the block function in
481 bundles of C<$number>.
482
483 If given a list of values whose length does not evenly divide by C<$number>,
484 the final call will be passed fewer elements than the others.
485
486 =cut
487
488 sub bundle_by(&@)
489 {
490    my $code = shift;
491    my $n = shift;
492
493    my @ret;
494    for( my ( $pos, $next ) = ( 0, $n ); $pos < @_; $pos = $next, $next += $n ) {
495       $next = @_ if $next > @_;
496       push @ret, $code->( @_[$pos .. $next-1] );
497    }
498    return @ret;
499 }
500
501 =head1 TODO
502
503 =over 4
504
505 =item * XS implementations
506
507 These functions are currently all written in pure perl. Some at least, may
508 benefit from having XS implementations to speed up their logic.
509
510 =item * Merge into L<List::Util> or L<List::MoreUtils>
511
512 This module shouldn't really exist. The functions should instead be part of
513 one of the existing modules that already contain many list utility functions.
514 Having Yet Another List Utilty Module just worsens the problem.
515
516 I have attempted to contact the authors of both of the above modules, to no
517 avail; therefore I decided it best to write and release this code here anyway
518 so that it is at least on CPAN. Once there, we can then see how best to merge
519 it into an existing module.
520
521 =back
522
523 =head1 AUTHOR
524
525 Paul Evans <leonerd@leonerd.org.uk>
526
527 =cut
528
529 0x55AA;