Lazyness, Impatienence, and Hubris:
Getting there on wheels we didn’t re-invent.
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
True Lazyness is what ain’t.
Not banging your head against a wall.
Especially one that someone else has padded.
Don’t re-invent the wheel.
Don’t maintain someone else’s code.
Don’t correct your mistakes with 20/20 hindsight.
The utility of lazyness
“Utility” modules:
Simple
Lightweight
No configuration.
Avoid side effects.
The utility of impatience
Many use XS.
Faster, cleaner, simpler code.
Some examples:
Scalar::Util
List::Util
List::MoreUtils
File::Spec::Funcitons
IO::Util
List::Util & Scalar::Util
Graham Barr’s originals.
Where it all started.
The original idea behind Scalar::Util:
Scalar::Util contains a selection of subroutines
that people have expressed would be nice to have in
the perl core, but the usage would not really be
high enough to warrant the use of a keyword, and
the size would be so small that being individual
extensions would be wasteful.
Graham Barr
Scalar Util
use Scalar::Util
qw
(
blessed dualvar isdual readonly refaddr reftype
tainted weaken isweak isvstring looks_like_number
set_prototype
);
Builtin: ‘ref’
$a = ‘foo’;
$b = [ 1 .. 10 ];
$c = bless $b, ‘Foo::Bar’;
ref $a ’’
ref $b ’ARRAY’
ref $c ’Foo::Bar’
Builtin: ‘ref’
$a = ‘foo’;
$b = [ 1 .. 10 ];
$c = bless $b, ‘Foo::Bar’;
ref $a ’’
ref $b ’ARRAY’ Maybe not a class?
ref $c ’Foo::Bar’
blessed: class name
$a = ‘foo’;
$b = [ 1 .. 10 ];
$c = bless $b, ‘Foo::Bar’;
blessed $a ’’
blessed $b ’’
blessed $c ’Foo::Bar’
reftype: structure
$a = ‘foo’;
$b = [ 1 .. 10 ];
$c = bless $b, ‘Foo::Bar’;
reftype $a ’’
reftype $b ’ARRAY’
reftype $c ’ARRAY’
Using blessed
sub construct
{
my $proto = shift;
bless [], blessed $proto || $proto
}
If-logic for object vs. class name.
Using blessed
Sanity-check for an object
my $obj = shift;
blessed $obj
or croak 'Not a class method.';
using refaddr
Each object has a unique address.
say refaddr []; ’94141673084392’
say refaddr []; ’94141673084413’
using refaddr
Object-specific data by address:
sub inside_out_data
{
state $cache = {};
my $obj = shift;
my $data = $cache{ refaddr $obj } //= {};
...
}
using refaddr
Inside of inside-out objects:
sub inside_out_data
{
state $cache = {};
my $obj = shift;
my $data = $cache{ refaddr $obj } //= {};
...
}
Numeric Input
Perly regex for a number?
m{^ d+ $}x
6
Numeric Input
Perly regex for a number?
m{^ [-+]?d+ $}x
+6
Numeric Input
Perly regex for a number?
m{^ [-+]?d+(?:[.]d*)? $}x
+6.023
Numeric Input
Perly regex for a number?
m{^ [-+]?d+(?:[.]d*)?(?ed+)? $}x
+6.023e23
Numeric Input
Perly regex for a number?
m{^ [-+]?d+(?:[.]d*)?(?ed+)? $}x
+6.023e+23 +6.023e-23 0e0
0x1A 0b1110101 02347
Numeric Input
Whatever running perl thinks is numeric.
looks_like_number $x
Come full circle:
https://perldoc.perl.org/perl5360delta
#builtin-functions-(experimental)
A new core module builtin has been added,
which provides documentation for new always-
present functions that are built into the
interpreter.
Exposing yourself
Core functions exported by Scalar::Util.
use builtin
qw(
true false is_bool
weaken unweaken is_weak
blessed refaddr reftype
created_as_string created_as_number
ceil floor
trim
);
Exposing yourselfe
# exposed through Scalar::Utils::reftype
use builtin qw( ‘reftype' );
say "Reference type of arrays is ", reftype [];
Exposing yourself
# strip leading and trailing witespace:
# space, newline, tabs...
my $clean = trim $input;
Exposing yourself
# expand an array into offset + value pairs
while( my( $i, $val ) = indexed @array )
{
...
}
Exposing yourself
# boolean-only value
true false is_boolean
List::Util
Has grown over time
reduce reductions any all
none notall first max maxstr
min minstr product sum sum0
pairs unpairs pairkeys pairvalues
pairgrep pairfirst pairmap
shuffle sample uniq uniqint
uniqnum uniqstr head tail
zip mesh
List::Util
List reduction
reduce reductions any all
none notall first max maxstr
min minstr product sum sum0
pairs unpairs pairkeys pairvalues
pairgrep pairfirst pairmap
shuffle sample uniq uniqint
uniqnum uniqstr head tail
zip mesh
List::Util
Key/Value & Pairs
reduce reductions any all
none notall first max maxstr
min minstr product sum sum0
pairs unpairs pairkeys pairvalues
pairgrep pairfirst pairmap
shuffle sample uniq uniqint
uniqnum uniqstr head tail
zip mesh
List::Util
Misc list
reduce reductions any all
none notall first max maxstr
min minstr product sum sum0
pairs unpairs pairkeys pairvalues
pairgrep pairfirst pairmap
shuffle sample uniq uniqint
uniqnum uniqstr head tail
zip mesh
List::Util
Allows declarative code.
Fewer loops and side effects.
Nice for larger lists.
Reducing your workload.
Behaves like a for-loop, accumulating the final
value:
$result = { $a combine $b } @list;
my $sum = reduce { $a += $b } …
my $max = reduce { $a > $b ? $a : $b } …
my $min = reduce { $a < $b ? $a : $b }
Reducing your workload.
Make a dir with parents on *NIX:
qx{ mkdir -p $dir };
die “Oops: $!” if $?;
Reducing your workload.
use List::Util qw( reduce );
use File::Spec::Functions qw( catdir splitdir );
sub mkdir_p
{
my $dir = shift;
reduce
{
use autodie qw( mkdir );
$a = catdir $a, $b;
-d $a || mkdir $a;
$a
} ( ‘’, splitdir $dir )
}
Reducing your workload.
use List::Util qw( reduce );
use File::Spec::Functions qw( catdir splitdir );
sub mkdir_p
{
my $dir = shift;
reduce
{
use autodie qw( mkdir );
$a = catdir $a, $b;
-d $a || mkdir $a;
$a
} ( ‘’, splitdir $dir )
}
Reducing your workload.
use List::Util qw( reduce );
use File::Spec::Functions qw( catdir splitdir );
sub mkdir_p
{
my $dir = shift;
reduce
{
use autodie qw( mkdir );
$a = catdir $a, $b;
-d $a || mkdir $a;
$a
} ( ‘’, splitdir $dir )
}
Reducing your workload.
use List::Util qw( reduce );
use File::Spec::Functions qw( catdir splitdir );
sub mkdir_p
{
my $dir = shift;
reduce
{
use autodie qw( mkdir );
$a = catdir $a, $b;
-d $a || mkdir $a;
$a
} ( ‘’, splitdir $dir )
}
reductions returns all results
use List::Util qw( reductions );
use File::Spec::Functions qw( catdir splitdir );
sub mkdir_p
{
use autodie qw( mkdir );
-d || mkdir
for reductions { catdir $a, $b }
( ‘’, splitdir $_[0] )
}
Easy to combine
Lack of side-effects:
reduce + splitdir + catdir.
Easy to mix and match due.
Useful design principle.
Unique list in input order
Different than extracting hash keys.
Hash keys have random order.
uniq preserves input order.
Useful for exterally sorted data:
uniq map { … } @input_data;
Unique list in input order
Comparison types:
uniq
uniqint
uniqnum
uniqstr
Do the Perly Shuffle
Non-destructive selection without replacement:
my @random_order = shuffle @input;
my @random_subset = sample $count => @input;
Pair op’s derived from Raku
Pair = [ key => value ].
Raku hash == list of pairs.
pairgrep
Compares key & value from list.
unpairs
Flattens pairs into list.
Search keys & values in one pass
$a is a key, $b is a value.
Compare key or value without separating them.
my %subset
= pairgrep
{
$a # key
$b # value
}
%bighash;
Search keys & values in one pass
Reeeeellly nice for filtering hash values!
my %subset
= pairgrep
{
$b % 2
}
%bighash;
Heads I win...
Simple list operations:
head( N ) == first N elements
head( -N ) == all but last n elemens.
tail( N ) == last N items from list.
tail( -N ) == all but last N items.
Simple things done easily
Simple fix for an obvious step:
Build a hash from keys and values.
my %hash = zip @keyz, @valz;
But wait! There’s more!!!
Junctions
Treatment of an empty list
all BLOCK LIST
all_u BLOCK LIST
any BLOCK LIST
any_u BLOCK LIST
none BLOCK LIST
none_u BLOCK LIST
notall BLOCK LIST
notall_u BLOCK LIST
one BLOCK LIST
one_u BLOCK LIST
Transformation
apply BLOCK LIST
insert_after BLOCK VALUE LIST
insert_after_string STRING VALUE LIST
pairwise BLOCK ARRAY1 ARRAY2
mesh ARRAY1 ARRAY2 [ ARRAY3 ... ]
zip ARRAY1 ARRAY2 [ ARRAY3 ... ]
zip6
zip_unflatten
listcmp ARRAY0 ARRAY1 [ ARRAY2 ... ]
arrayify LIST[,LIST[,LIST...]]
uniq LIST
distinct LIST
singleton LIST
duplicates LIST
frequency LIST
occurrences LIST
mode LIST
slide BLOCK LIST
Partitioning
after BLOCK LIST
after_incl BLOCK LIST
before BLOCK LIST
before_incl BLOCK LIST
part BLOCK LIST
samples COUNT LIST
Iteration
each_array ARRAY1 ARRAY2 ...
each_arrayref LIST
natatime EXPR, LIST
slideatatime STEP, WINDOW, LIST
Searching
firstval BLOCK LIST
first_value BLOCK LIST
onlyval BLOCK LIST
only_value BLOCK LIST
lastval BLOCK LIST
last_value BLOCK LIST
firstres BLOCK LIST
first_result BLOCK LIST
onlyres BLOCK LIST
only_result BLOCK LIST
lastres BLOCK LIST
last_result BLOCK LIST
indexes BLOCK LIST
firstidx BLOCK LIST
first_index BLOCK LIST
onlyidx BLOCK LIST
only_index BLOCK LIST
lastidx BLOCK LIST
last_index BLOCK LIST
Sorting
sort_by BLOCK LIST
nsort_by BLOCK LIST
qsort BLOCK ARRAY
Searching in sorted Lists
bsearch BLOCK LIST
bsearchidx BLOCK LIST
bsearch_index BLOCK LIST
lower_bound BLOCK LIST
upper_bound BLOCK LIST
equal_range BLOCK LIST
Operations on sorted Lists
binsert BLOCK ITEM LIST
bsearch_insert BLOCK ITEM LIST
bremove BLOCK LIST
bsearch_remove BLOCK LIST
Counting and calculation
true BLOCK LIST
false BLOCK LIST
reduce_0 BLOCK LIST
reduce_1 BLOCK LIST
reduce_u BLOCK LIST
minmax LIST
minmaxstr LIST
List::MoreUtils
Junctions
Treatment of an empty list
all BLOCK LIST
all_u BLOCK LIST
any BLOCK LIST
any_u BLOCK LIST
none BLOCK LIST
none_u BLOCK LIST
notall BLOCK LIST
notall_u BLOCK LIST
one BLOCK LIST
one_u BLOCK LIST
Transformation
apply BLOCK LIST
insert_after BLOCK VALUE LIST
insert_after_string STRING VALUE LIST
pairwise BLOCK ARRAY1 ARRAY2
mesh ARRAY1 ARRAY2 [ ARRAY3 ... ]
zip ARRAY1 ARRAY2 [ ARRAY3 ... ]
zip6
zip_unflatten
listcmp ARRAY0 ARRAY1 [ ARRAY2 ... ]
arrayify LIST[,LIST[,LIST...]]
uniq LIST
distinct LIST
singleton LIST
duplicates LIST
frequency LIST
occurrences LIST
mode LIST
slide BLOCK LIST
Partitioning
after BLOCK LIST
after_incl BLOCK LIST
before BLOCK LIST
before_incl BLOCK LIST
part BLOCK LIST
samples COUNT LIST
Iteration
each_array ARRAY1 ARRAY2 ...
each_arrayref LIST
natatime EXPR, LIST
slideatatime STEP, WINDOW, LIST
Searching
firstval BLOCK LIST
first_value BLOCK LIST
onlyval BLOCK LIST
only_value BLOCK LIST
lastval BLOCK LIST
last_value BLOCK LIST
firstres BLOCK LIST
first_result BLOCK LIST
onlyres BLOCK LIST
only_result BLOCK LIST
lastres BLOCK LIST
last_result BLOCK LIST
indexes BLOCK LIST
firstidx BLOCK LIST
first_index BLOCK LIST
onlyidx BLOCK LIST
only_index BLOCK LIST
lastidx BLOCK LIST
last_index BLOCK LIST
Sorting
sort_by BLOCK LIST
nsort_by BLOCK LIST
qsort BLOCK ARRAY
Searching in sorted Lists
bsearch BLOCK LIST
bsearchidx BLOCK LIST
bsearch_index BLOCK LIST
lower_bound BLOCK LIST
upper_bound BLOCK LIST
equal_range BLOCK LIST
Operations on sorted Lists
binsert BLOCK ITEM LIST
bsearch_insert BLOCK ITEM LIST
bremove BLOCK LIST
bsearch_remove BLOCK LIST
Counting and calculation
true BLOCK LIST
false BLOCK LIST
reduce_0 BLOCK LIST
reduce_1 BLOCK LIST
reduce_u BLOCK LIST
minmax LIST
minmaxstr LIST
IO::Util
Capture stdout or stderr in a scalar:
my $output_ref = capture { ... print ... };
IO::Util
Capture stdout or stderr in a scalar:
my $output_ref
= capture
{
print ‘this’;
...
print ‘that’;
};
IO::Util
Capture stdout or stderr in a scalar:
my $output_ref
= capture
{
say “Output from ‘$exec’”, qx{ $exec };
};
Hundreds more...
“::Util” on metacpan.
Hundreds of modules.
Lots of ways not to re-invent the wheel.

Wheels we didn't re-invent: Perl's Utility Modules

  • 1.
    Lazyness, Impatienence, andHubris: Getting there on wheels we didn’t re-invent. Steven Lembark Workhorse Computing lembark@wrkhors.com
  • 2.
    True Lazyness iswhat ain’t. Not banging your head against a wall. Especially one that someone else has padded. Don’t re-invent the wheel. Don’t maintain someone else’s code. Don’t correct your mistakes with 20/20 hindsight.
  • 3.
    The utility oflazyness “Utility” modules: Simple Lightweight No configuration. Avoid side effects.
  • 4.
    The utility ofimpatience Many use XS. Faster, cleaner, simpler code.
  • 5.
  • 6.
    List::Util & Scalar::Util GrahamBarr’s originals. Where it all started.
  • 7.
    The original ideabehind Scalar::Util: Scalar::Util contains a selection of subroutines that people have expressed would be nice to have in the perl core, but the usage would not really be high enough to warrant the use of a keyword, and the size would be so small that being individual extensions would be wasteful. Graham Barr
  • 8.
    Scalar Util use Scalar::Util qw ( blesseddualvar isdual readonly refaddr reftype tainted weaken isweak isvstring looks_like_number set_prototype );
  • 9.
    Builtin: ‘ref’ $a =‘foo’; $b = [ 1 .. 10 ]; $c = bless $b, ‘Foo::Bar’; ref $a ’’ ref $b ’ARRAY’ ref $c ’Foo::Bar’
  • 10.
    Builtin: ‘ref’ $a =‘foo’; $b = [ 1 .. 10 ]; $c = bless $b, ‘Foo::Bar’; ref $a ’’ ref $b ’ARRAY’ Maybe not a class? ref $c ’Foo::Bar’
  • 11.
    blessed: class name $a= ‘foo’; $b = [ 1 .. 10 ]; $c = bless $b, ‘Foo::Bar’; blessed $a ’’ blessed $b ’’ blessed $c ’Foo::Bar’
  • 12.
    reftype: structure $a =‘foo’; $b = [ 1 .. 10 ]; $c = bless $b, ‘Foo::Bar’; reftype $a ’’ reftype $b ’ARRAY’ reftype $c ’ARRAY’
  • 13.
    Using blessed sub construct { my$proto = shift; bless [], blessed $proto || $proto } If-logic for object vs. class name.
  • 14.
    Using blessed Sanity-check foran object my $obj = shift; blessed $obj or croak 'Not a class method.';
  • 15.
    using refaddr Each objecthas a unique address. say refaddr []; ’94141673084392’ say refaddr []; ’94141673084413’
  • 16.
    using refaddr Object-specific databy address: sub inside_out_data { state $cache = {}; my $obj = shift; my $data = $cache{ refaddr $obj } //= {}; ... }
  • 17.
    using refaddr Inside ofinside-out objects: sub inside_out_data { state $cache = {}; my $obj = shift; my $data = $cache{ refaddr $obj } //= {}; ... }
  • 18.
    Numeric Input Perly regexfor a number? m{^ d+ $}x 6
  • 19.
    Numeric Input Perly regexfor a number? m{^ [-+]?d+ $}x +6
  • 20.
    Numeric Input Perly regexfor a number? m{^ [-+]?d+(?:[.]d*)? $}x +6.023
  • 21.
    Numeric Input Perly regexfor a number? m{^ [-+]?d+(?:[.]d*)?(?ed+)? $}x +6.023e23
  • 22.
    Numeric Input Perly regexfor a number? m{^ [-+]?d+(?:[.]d*)?(?ed+)? $}x +6.023e+23 +6.023e-23 0e0 0x1A 0b1110101 02347
  • 23.
    Numeric Input Whatever runningperl thinks is numeric. looks_like_number $x
  • 24.
    Come full circle: https://perldoc.perl.org/perl5360delta #builtin-functions-(experimental) Anew core module builtin has been added, which provides documentation for new always- present functions that are built into the interpreter.
  • 25.
    Exposing yourself Core functionsexported by Scalar::Util. use builtin qw( true false is_bool weaken unweaken is_weak blessed refaddr reftype created_as_string created_as_number ceil floor trim );
  • 26.
    Exposing yourselfe # exposedthrough Scalar::Utils::reftype use builtin qw( ‘reftype' ); say "Reference type of arrays is ", reftype [];
  • 27.
    Exposing yourself # stripleading and trailing witespace: # space, newline, tabs... my $clean = trim $input;
  • 28.
    Exposing yourself # expandan array into offset + value pairs while( my( $i, $val ) = indexed @array ) { ... }
  • 29.
    Exposing yourself # boolean-onlyvalue true false is_boolean
  • 30.
    List::Util Has grown overtime reduce reductions any all none notall first max maxstr min minstr product sum sum0 pairs unpairs pairkeys pairvalues pairgrep pairfirst pairmap shuffle sample uniq uniqint uniqnum uniqstr head tail zip mesh
  • 31.
    List::Util List reduction reduce reductionsany all none notall first max maxstr min minstr product sum sum0 pairs unpairs pairkeys pairvalues pairgrep pairfirst pairmap shuffle sample uniq uniqint uniqnum uniqstr head tail zip mesh
  • 32.
    List::Util Key/Value & Pairs reducereductions any all none notall first max maxstr min minstr product sum sum0 pairs unpairs pairkeys pairvalues pairgrep pairfirst pairmap shuffle sample uniq uniqint uniqnum uniqstr head tail zip mesh
  • 33.
    List::Util Misc list reduce reductionsany all none notall first max maxstr min minstr product sum sum0 pairs unpairs pairkeys pairvalues pairgrep pairfirst pairmap shuffle sample uniq uniqint uniqnum uniqstr head tail zip mesh
  • 34.
    List::Util Allows declarative code. Fewerloops and side effects. Nice for larger lists.
  • 35.
    Reducing your workload. Behaveslike a for-loop, accumulating the final value: $result = { $a combine $b } @list; my $sum = reduce { $a += $b } … my $max = reduce { $a > $b ? $a : $b } … my $min = reduce { $a < $b ? $a : $b }
  • 36.
    Reducing your workload. Makea dir with parents on *NIX: qx{ mkdir -p $dir }; die “Oops: $!” if $?;
  • 37.
    Reducing your workload. useList::Util qw( reduce ); use File::Spec::Functions qw( catdir splitdir ); sub mkdir_p { my $dir = shift; reduce { use autodie qw( mkdir ); $a = catdir $a, $b; -d $a || mkdir $a; $a } ( ‘’, splitdir $dir ) }
  • 38.
    Reducing your workload. useList::Util qw( reduce ); use File::Spec::Functions qw( catdir splitdir ); sub mkdir_p { my $dir = shift; reduce { use autodie qw( mkdir ); $a = catdir $a, $b; -d $a || mkdir $a; $a } ( ‘’, splitdir $dir ) }
  • 39.
    Reducing your workload. useList::Util qw( reduce ); use File::Spec::Functions qw( catdir splitdir ); sub mkdir_p { my $dir = shift; reduce { use autodie qw( mkdir ); $a = catdir $a, $b; -d $a || mkdir $a; $a } ( ‘’, splitdir $dir ) }
  • 40.
    Reducing your workload. useList::Util qw( reduce ); use File::Spec::Functions qw( catdir splitdir ); sub mkdir_p { my $dir = shift; reduce { use autodie qw( mkdir ); $a = catdir $a, $b; -d $a || mkdir $a; $a } ( ‘’, splitdir $dir ) }
  • 41.
    reductions returns allresults use List::Util qw( reductions ); use File::Spec::Functions qw( catdir splitdir ); sub mkdir_p { use autodie qw( mkdir ); -d || mkdir for reductions { catdir $a, $b } ( ‘’, splitdir $_[0] ) }
  • 42.
    Easy to combine Lackof side-effects: reduce + splitdir + catdir. Easy to mix and match due. Useful design principle.
  • 43.
    Unique list ininput order Different than extracting hash keys. Hash keys have random order. uniq preserves input order. Useful for exterally sorted data: uniq map { … } @input_data;
  • 44.
    Unique list ininput order Comparison types: uniq uniqint uniqnum uniqstr
  • 45.
    Do the PerlyShuffle Non-destructive selection without replacement: my @random_order = shuffle @input; my @random_subset = sample $count => @input;
  • 46.
    Pair op’s derivedfrom Raku Pair = [ key => value ]. Raku hash == list of pairs. pairgrep Compares key & value from list. unpairs Flattens pairs into list.
  • 47.
    Search keys &values in one pass $a is a key, $b is a value. Compare key or value without separating them. my %subset = pairgrep { $a # key $b # value } %bighash;
  • 48.
    Search keys &values in one pass Reeeeellly nice for filtering hash values! my %subset = pairgrep { $b % 2 } %bighash;
  • 49.
    Heads I win... Simplelist operations: head( N ) == first N elements head( -N ) == all but last n elemens. tail( N ) == last N items from list. tail( -N ) == all but last N items.
  • 50.
    Simple things doneeasily Simple fix for an obvious step: Build a hash from keys and values. my %hash = zip @keyz, @valz;
  • 51.
    But wait! There’smore!!! Junctions Treatment of an empty list all BLOCK LIST all_u BLOCK LIST any BLOCK LIST any_u BLOCK LIST none BLOCK LIST none_u BLOCK LIST notall BLOCK LIST notall_u BLOCK LIST one BLOCK LIST one_u BLOCK LIST Transformation apply BLOCK LIST insert_after BLOCK VALUE LIST insert_after_string STRING VALUE LIST pairwise BLOCK ARRAY1 ARRAY2 mesh ARRAY1 ARRAY2 [ ARRAY3 ... ] zip ARRAY1 ARRAY2 [ ARRAY3 ... ] zip6 zip_unflatten listcmp ARRAY0 ARRAY1 [ ARRAY2 ... ] arrayify LIST[,LIST[,LIST...]] uniq LIST distinct LIST singleton LIST duplicates LIST frequency LIST occurrences LIST mode LIST slide BLOCK LIST Partitioning after BLOCK LIST after_incl BLOCK LIST before BLOCK LIST before_incl BLOCK LIST part BLOCK LIST samples COUNT LIST Iteration each_array ARRAY1 ARRAY2 ... each_arrayref LIST natatime EXPR, LIST slideatatime STEP, WINDOW, LIST Searching firstval BLOCK LIST first_value BLOCK LIST onlyval BLOCK LIST only_value BLOCK LIST lastval BLOCK LIST last_value BLOCK LIST firstres BLOCK LIST first_result BLOCK LIST onlyres BLOCK LIST only_result BLOCK LIST lastres BLOCK LIST last_result BLOCK LIST indexes BLOCK LIST firstidx BLOCK LIST first_index BLOCK LIST onlyidx BLOCK LIST only_index BLOCK LIST lastidx BLOCK LIST last_index BLOCK LIST Sorting sort_by BLOCK LIST nsort_by BLOCK LIST qsort BLOCK ARRAY Searching in sorted Lists bsearch BLOCK LIST bsearchidx BLOCK LIST bsearch_index BLOCK LIST lower_bound BLOCK LIST upper_bound BLOCK LIST equal_range BLOCK LIST Operations on sorted Lists binsert BLOCK ITEM LIST bsearch_insert BLOCK ITEM LIST bremove BLOCK LIST bsearch_remove BLOCK LIST Counting and calculation true BLOCK LIST false BLOCK LIST reduce_0 BLOCK LIST reduce_1 BLOCK LIST reduce_u BLOCK LIST minmax LIST minmaxstr LIST
  • 52.
    List::MoreUtils Junctions Treatment of anempty list all BLOCK LIST all_u BLOCK LIST any BLOCK LIST any_u BLOCK LIST none BLOCK LIST none_u BLOCK LIST notall BLOCK LIST notall_u BLOCK LIST one BLOCK LIST one_u BLOCK LIST Transformation apply BLOCK LIST insert_after BLOCK VALUE LIST insert_after_string STRING VALUE LIST pairwise BLOCK ARRAY1 ARRAY2 mesh ARRAY1 ARRAY2 [ ARRAY3 ... ] zip ARRAY1 ARRAY2 [ ARRAY3 ... ] zip6 zip_unflatten listcmp ARRAY0 ARRAY1 [ ARRAY2 ... ] arrayify LIST[,LIST[,LIST...]] uniq LIST distinct LIST singleton LIST duplicates LIST frequency LIST occurrences LIST mode LIST slide BLOCK LIST Partitioning after BLOCK LIST after_incl BLOCK LIST before BLOCK LIST before_incl BLOCK LIST part BLOCK LIST samples COUNT LIST Iteration each_array ARRAY1 ARRAY2 ... each_arrayref LIST natatime EXPR, LIST slideatatime STEP, WINDOW, LIST Searching firstval BLOCK LIST first_value BLOCK LIST onlyval BLOCK LIST only_value BLOCK LIST lastval BLOCK LIST last_value BLOCK LIST firstres BLOCK LIST first_result BLOCK LIST onlyres BLOCK LIST only_result BLOCK LIST lastres BLOCK LIST last_result BLOCK LIST indexes BLOCK LIST firstidx BLOCK LIST first_index BLOCK LIST onlyidx BLOCK LIST only_index BLOCK LIST lastidx BLOCK LIST last_index BLOCK LIST Sorting sort_by BLOCK LIST nsort_by BLOCK LIST qsort BLOCK ARRAY Searching in sorted Lists bsearch BLOCK LIST bsearchidx BLOCK LIST bsearch_index BLOCK LIST lower_bound BLOCK LIST upper_bound BLOCK LIST equal_range BLOCK LIST Operations on sorted Lists binsert BLOCK ITEM LIST bsearch_insert BLOCK ITEM LIST bremove BLOCK LIST bsearch_remove BLOCK LIST Counting and calculation true BLOCK LIST false BLOCK LIST reduce_0 BLOCK LIST reduce_1 BLOCK LIST reduce_u BLOCK LIST minmax LIST minmaxstr LIST
  • 53.
    IO::Util Capture stdout orstderr in a scalar: my $output_ref = capture { ... print ... };
  • 54.
    IO::Util Capture stdout orstderr in a scalar: my $output_ref = capture { print ‘this’; ... print ‘that’; };
  • 55.
    IO::Util Capture stdout orstderr in a scalar: my $output_ref = capture { say “Output from ‘$exec’”, qx{ $exec }; };
  • 56.
    Hundreds more... “::Util” onmetacpan. Hundreds of modules. Lots of ways not to re-invent the wheel.