Name
List::Stream - Simple Java-like lazy, functionally-pure manipulation of lists.
Synopsis
List::Stream provides simple functionality for manipulating list data in a functional, and simple way. List::Stream is lazy, meaning it stores all operations internally, so that they're only evaluated when entirely necessary.
Example
use
List::Stream;
use
DBI;
my
$stream
= stream DBI->selectall_array(
'SELECT * FROM users'
, {
Slice
=> {}});
# create a sub stream that maps all users to their role
my
$mapped_stream
=
$stream
->
map
(
sub
{
$_
->{role} });
# to_list applies all pending lazy operations, ie map.
my
$number_of_users
=
$mapped_stream
->filter(
sub
{
$_
eq
'USER'
})->count;
my
$number_of_admins
=
$mapped_stream
->filter(
sub
{
$_
eq
'ADMIN'
})->count;
my
%users_by_user_id
=
$stream
->to_hash(
sub
{
$_
->{user_id} },
sub
{
$_
});
my
$it
=
$mapped_stream
->to_iterator;
stream
Create a new List::Stream instance from a list.
map
Map data in a stream over a unary function. A -> B
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
@data
=
$stream
->
map
(
sub
{
$_
+ 1 })
->to_list;
say
@data
;
# 2, 3, 4, 5
reduce
Reduce data to a single element, via a bi-function, with the default accumlator passed as the second arg. Retrieved by List::Stream::first. If the value reduced to is an ArrayRef, the streams data becomes the ArrayRef.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
my
$sum
=
$stream
->reduce(
sub
{
my
(
$elem
,
$accum
) =
@_
;
$accum
+=
$elem
;
}, 0)
# pass default
->first;
say
$sum
;
# 10
filter
Filters elements from the stream if they do not pass a predicate.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
@data
=
$stream
->filter(
sub
{
$_
>= 3 })
->to_list;
say
@data
;
# 3, 4
flat_map
Passes the contents of the stream to a mapping function, the mapping function must then return a List::Stream.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
@data
=
$stream
->flat_map(
sub
{
stream(
@_
)->
map
(
sub
{
$_
* 2 })
})
->to_list;
say
@data
;
# 2, 4, 6, 8
unique
Filters the stream down to only unique values. This uses a HASH to determine uniqueness.
use
List::Stream;
my
$stream
= stream
qw(a a b c b d e)
;
my
@values
=
$stream
->unique->to_list;
say
@values
;
# a, b, c, d, e
If you'd like to use another value to represent the value in the uniquness check you can pass a sub-routine that will be passed the value, and the result of the sub-routine will be the uniqueness identifier.
use
List::Stream;
my
$stream
= stream ({
id
=> 123 }, {
id
=> 456 }, {
id
=> 123 });
my
@values
=
$stream
->unique(
sub
{
$_
->{id} })->to_list;
say
@values
;
# { id => 123 }, { id => 456 }
skip
Skips n
elements in the stream, discarding them.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
@data
=
$stream
->skip(2)
->to_list;
say
@data
;
# 3, 4
for_each
Applies a void context unary-function to the stream.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream
@data
;
$stream
->for_each(
sub
{
say
$_
; });
# says 1, then 2, then 3, then 4
to_list
Applies all pending operations on the stream, and collects them to an array.
my
@data
= (1, 2, 3, 4);
my
$stream
= stream(
@data
)->
map
(
sub
{
$_
+ 1 });
# The mapping hasn't happened yet, we're lazy.
@data
=
$stream
->to_list;
say
@data
;
# 2, 3, 4, 5
to_hash
Applies all pending operations on the stream, and collects them to a hash.
my
@data
= (1, 2, 3, 4);
my
$stream
= stream(
@data
)->
map
(
sub
{
$_
+ 1 });
# The mapping hasn't happened yet, we're lazy.
my
%hash
=
$stream
->to_hash;
say
%hash
;
# 2 => 3, 4 => 5
You may also provide a key, and value mapper to be applied to each element.
my
@data
= (1, 2, 3, 4);
my
$stream
= stream(
@data
)->
map
(
sub
{
$_
+ 1 });
my
%hash
=
$stream
->to_hash(
sub
{
$_
* 2 },
sub
{
$_
});
say
%hash
;
# 4 => 2, 6 => 3, 8 => 4, 10 => 5
first
Gets the first element of the stream, and applies all pending operations. This is useful when using List::Stream::reduce
, when you've reduced to a single value.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream(
@data
)->
map
(
sub
{
$_
+ 1 });
my
$first
=
$stream
->first;
say
$first
;
# 2
Since reduce reduces the stream to a single element, first
can be used to get the reduced value.
use
List::Stream;
my
@data
= (1, 2, 3, 4);
my
$stream
= stream(
@data
)
->
map
(
sub
{
$_
+ 1 })
->reduce(
sub
{
my
(
$elem
,
$accum
) =
@_
;
$elem
+=
$accum
}, 0);
my
$first
=
$stream
->first;
say
$first
;
# 14
is_empty
Applies all pending operations, and returns true if the stream is empty or false if the stream has at least one value.
to_iterator
Applies all pending operations on the stream, and returns an iterator in the form of a sub-routine.
use
List::Stream;
my
$stream
= stream(
qw(a b c d e f g)
)
->
map
(
sub
{
$_
.
'f'
});
my
$it
=
$stream
->to_iterator;
while
(
my
$val
=
$it
->()) {
say
$val
;
}
count
Applies all pending operations on the stream, and returns the count of elements in the stream.
my
$stream
= stream(
qw(a b c d e f g)
)
->
map
(
sub
{
$_
.
'f'
});
my
$length
=
$stream
->
length
;
say
$length
;
# 7