The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

=encoding utf8
=head1 NAME
Module::Generic::Array - An Array Manipulation Object Class
=head1 SYNOPSIS
my $ar = Module::Generic::Array->new( [qw( Joe John Mary )] );
printf( "There are %d people\n", $ar->length );
my $object = $ar->as_array; # returns the array object
my $str = $ar->as_string; # Joe John Mary
my $hash = $ar->as_hash; # Joe => 0, John => 1, Mary => 2
my $hash = $ar->as_hash( start_from => 2 ); # Joe => 2, John => 3, Mary => 4
my $lines = Module::Generic::Array->new( \@lines );
$lines->chomp; # Now @lines does not contain any \n at the end
my $ar2 = $ar->clone;
$ar->contains( 'Joe' ); # true
# Same as splice:
my $removed = $ar->delete( 'John', 1 ); # 'John' is returned
$removed->length; # 1
my @removed = $ar->delete( 'John', 1 );
$ar->each(sub
{
print( "I got $_\n" );
# could also write:
# print( "I got $_[1] at offset $_[0]\n" );
$ar->break; # stop looping
});
$ar->empty; # $ar is now empty
# Same as contains:
$ar->exists( 'Mary' ); # true
my $even = $ar->even; # Joe Mary
$ar->first; # Joe
$ar->for(sub
{
my( $i, $val ) = @_;
# do something
});
$ar->foreach(sub
{
my $val = shift( @_ );
# do something
});
$ar->get(2); # Mary
my $elements = $ar->grep(sub{ $_ eq 'John' });
$elements->length; # 1
my @elements = $ar->grep(sub{ $_ eq 'John' });
my $elements = $ar->grep(qr/^Jo/);
$elements->length; # 2
my @elements = $ar->grep(qr/^Jo/);
# Same as exists:
$ar->has( 'Mary' ); # true
# Get 'Mary' in object context
print $ar->index(2)->substr( 0, 2 ); # Ma
my $name = $ar->index(2);
print "Name is: $name\n"; " Name is: Mary
my $it = $ar->iterator;
print $it->next; # Joe
print "Names are: ", $ar->join( ', ' ), "\n"; # Names are: Joe, John, Mary
print $ar->keys->as_string, "\n"; # 0 1 2
print $ar->last->substr( 0, 2 ); # Ma
$ar->length; # 3 (because there are 3 elements in the array object)
my @people = $a->list; # @people now is ( "Joe", "John", "Mary" )
print( $a->map(sub{ $_->value })->join( "\n" ), "\n" );
my $a = Module::Generic::Array->new( [qw( Jack John Peter )] );
my $b = Module::Generic::Array->new( [qw( Gabriel Raphael Emmanuel )] );
$a->merge( $b );
print( $a->join( ' ' ), "\n" ); # Jack John Peter Gabriel Raphael Emmanuel
my $a = Module::Generic::Array->new( [qw( 1 2 3 4 5 6 7 8 9 10 )] ); my
$odd = $a->odd; say "@$odd"; # 2 4 6 8 10
my $a = $m->new_array( [qw( Jack John Peter Gabriel Raphael Emmanuel )] );
print( $a->offset( 2, 3 )->join( ' ' ), "\n" ); # John Peter Gabriel
my $a = Module::Generic::Array->new( [qw( Hello world )] );
# called in object context
say $a->pop->length; # 5 (returns a Module::Generic::Scalar in object context)
# but
say $a->pop; # returns "world" as a regular string
my $a = Module::Generic::Array->new( [qw( John Jack Peter )] );
my $offset = $a->pos( 'Jack' ); # returns 1
$a->pos( 'Bob' ); # Returns undef
my $hash = { first_name => 'John', last_name => 'Doe' };
$a->push( $hash );
$a->pos( $hash ); # Returns 3
my $a = Module::Generic::Array->new( [qw( John Jack Peter )] );
my $b = Module::Generic::Array->new( [qw( Gabriel Raphael Emmanuel )] );
$a->push( $b ); # or you can do $a->push( $b->list );
# Now $a contains something like: John Jack Peter Module::Generic::Array=ARRAY(0x557d2c2983e8)
# Equally
$a->merge( $b ); # $a now is: John Jack Peter Gabriel Raphael Emmanuel
my $ar = Module::Generic::Array->new( [qw( John Joe Mary )]);
$ar->push_arrayref( [qw( Jack Peter )] );
print( $ar->join( "," ), "\n" );
# Now prints: John, Joe, Mary, Jack, Peter
my $dummy = { class => 'Hello' };
my $a = Module::Generic::Array->new( ['Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', 'Raphael', 'Emmanuel'] );
$a->remove( $dummy, qw( John Paul Peter Emmanuel ) );
say( "@$a" ); # Jack Gabriel Raphael
$ar->reset; # Now the array object is empty
$ar->for(sub
{
my( $i, $n ) = @_;
$pos = $n;
$b->for(sub
{
my( $j, $v ) = @_;
# Tell loop for array $a to stop
$a->break if( $n == 7 && $v == 27 );
});
# some more stuff here....
});
my $a = Module::Generic::Array->new( [qw( Jack John Peter Paul Gabriel Raphael Emmanuel )] );
$a->for(sub
{
my( $i, $n ) = @_;
# tell it to skip Peter
$a->return(+1) if( $n eq 'John' );
# No need to return a true value anymore
# Ending the loop must be explicitly expressed using break
});
$ar->reverse; # Mary John Joe
$ar->scalar; # 3 (returns the size of the array object)
$a->set( qw( John Jack Peter ) ); # Using an array of elements
$a->set( [qw( John Jack Peter )] ); # Using an array reference of elements
$a->set( $a2 ); # Using another array object, whatever its class may be
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->shift->length; # 5
# but
say $a->shift; # returns "Hello" as a regular string
$ar->size; 2 (size of the array object starting from 0)
$ar->sort; Joe John Mary
my $a = Module::Generic::Array->new( [qw( I disapprove of what you say, but I will defend to the death your right to say it )] );
say $a->splice( 7, 3 ); # returns a list containing "I", "will", "defend"
say $a->splice( 7 ); # returns a list containing "I", "will", "defend", "to", "the", "death", "your", "right", "to", "say", "it"
say a->splice( 7, 3 )->length; # returns 3 obviously
say a->splice( 7 )->length; # returns 11
my $a = $ar->split( qr/[[:blank:]\h]+/, "I disapprove of what you say, but I will defend to the death your right to say it" );
$a->length; # 18
# or in list context and using the method as a class method
my @words = Module::Generic::Array->split( qr/[[:blank:]\h]+/, "I disapprove of what you say, but I will defend to the death your right to say it" );
$ar->undef; # same as reset. Now the array object is empty
my $dummy = { class => 'Hello' };
my $a = Module::Generic::Array->new( ['Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', $dummy, 'Peter', 'Raphael', 'Emmanuel'] );
my $b = $a->unique;
# $b now contains: 'Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', 'Raphael', 'Emmanuel'
# or to update $a directly (in place):
$a->unique(1);
$ar->unshift( qw( Peter Gabriel ) ); # Now array is Peter Gabriel Joe John Mary
$ar->values; # Peter Gabriel Joe John Mary
# Adding one more
$ar->push( "Jack" );
=head1 VERSION
v2.1.0
=head1 DESCRIPTION
The purpose of this class/package is to provide an object-oriented approach at array manipulation
=head1 METHODS
=head2 new
Provided with an optional array reference or an array object such as L<Module::Generic::Array>, this will create a new object and return it.
=head2 append
This is an alias for L</push>
=head2 as_hash
Returns an hash reference with the keys being the array elements and the hash values their offset value.
It takes an optional hash of options:
=over 4
=item * C<start_from>
If true, the offset values will start from the number provided and not 0, as it is the case by default.
=back
Example:
my $a = Module::Generic::Array->new( [qw( Jack John Peter )] );
my $h = $a->as_hash({ start_from => 1 });
# $h now is:
{
Jack => 1,
John => 2,
Peter => 3,
}
=head2 as_array
This simply returns the current object, so it does nothing special. It is here, so that one can blindly call C<as_array> on any of the L<Module::Generic::Array>, L<Module::Generic::Boolean>, L<Module::Generic::Number> or L<Module::Generic::Scalar> object and get an L<Module::Generic::Array> object in return.
=head2 as_string
Returns the array as string, which is essentially the same as C<"@array">
It takes an optional boolean value that, if true, will sort the array before.
=head2 break
Instructs the loop of the given object to exit the loop.
You can return on the call of break to immediately exit any loop you are in. For example:
$a->for(sub
{
# Do something
return( $a->break ) if( $true );
# And something more
});
It also works if you are within another loop, because L</break> returns a code that exit the current loop as well. For example:
$a->for(sub
{
# Do something
$b->foreach(sub
{
# Now exit the $b loop and the $a loop as well
return( $a->break ) if( $true );
# And something more
});
});
It will not work though if you are in 3 loops deep. That's the limitation for now. For example:
$a->for(sub
{
# Do something
$b->foreach(sub
{
$c->foreach(sub
{
# Now exit the $c loop and the $a loop only at the end of the $b loop iteration
return( $a->break ) if( $true );
# And something more
});
});
});
=head2 callback
Sets or gets a callback on the array object. You can set 2 types of callback: C<add> or C<remove> which will be called respectively when you add something to the array or when you remove something from it.
It does this by tieing the array to its internal class C<Module::Generic::Array::Tie> that will call the C<add> or C<remove> callback when data is being added or removed, no matter how, i.e. be it through the methods of this class, or by directly trying to add data to it:
use Scalar::Util qw( blessed );
my $a = Module::Generic::Array->new();
$a->callback( add => sub
{
my( $pos, $ref ) = @_;
return unless( blessed( $ref->[0] ) && $ref->[0]->isa( 'MyPackage') );
return(1);
});
$a->push( $some_object );
# or
push( @$a, $some_object );
In both cases above the object from class C<MyPackage> will be added, and if it were some other data, i.e. not from the class C<MyPackage>, the data would not be added to the array.
So, the callback must return true to allow the data to be added, or C<undef> to refuse. Returning an empty string or 0 will not work to be considered a rejection even though it is a false value.
Both C<add> and C<remove> callbacks receives an hash reference as its sole arguments. This hash reference can also be accessed within the callback subroutine as C<$_>
The C<add> callback receives an hash reference with the following properties:
=over 4
=item added
An array reference of values being added, so you can inspect them. This is also available with the C<data> property
=item caller
An array reference of the values returned by L<perlfunc/caller> indicating where this callback was originally triggered.
=item data
An array reference of values being added, so you can inspect them. This is also available with the C<aded> property
=item start
The offset position (starting from 0)
=item type
The callback type: C<add>
=back
The C<remove> callback works the same way, but for any operation that tries to remove data from the array. It receives an hash reference with the following properties:
=over 4
=item caller
An array reference of the values returned by L<perlfunc/caller> indicating where this callback was originally triggered.
=item data
An array reference of the values being removed. This is also available with the C<removed> property
=item end
The end position (starting from 0)
=item removed
An array reference of the values being removed. This is also available with the C<data> property
=item start
The start position
=item type
The callback type: C<remove>
=back
my $a = Module::Generic::Array->new();
$a->callback( remove => sub
{
my $def = shift( @_ );
my( $start, $end ) = @$def{qw( start end )};
printf( STDERR "Called from package %s at line %d\n", @{$def->{caller}}[0,2] );
# Do some check to accept or reject
return(1); # always return true to accept
});
$a->splice( 3, 4 ); # Removing 4 elements starting from the position 3
This example above would call the callback passing it the value 3 and 7 since 7 is the last position in the range of data being removed.
my $removed = $a->shift;
Here, the arguments received by the callback would be 0 and 0.
To replace a callback, simply add another one. It will replace the previous one.
You can get the callback code associated with a callback by calling C<callback> with one argument: the callback type.
my $code_ref = $a->callback( 'add' );
To remove a callback, pass C<undef>:
$a->callback( add => undef );
$a->callback( remove => undef );
By default, an array object is not tied to C<Module::Generic::Array::Tie> and no callback are set nor used. Be mindful when using callbacks since it will slow things down a little bit even though it is s very thin layer.
See L<perltie> for more information on tieing data.
=head2 chomp
For example, assuming a file whose lines were read onto an array, and each being terminated by C<\n>, the following will remove each line's new lines characters.
my $lines = Module::Generic::Array->new( \@lines );
$lines->chomp;
# Now @lines does not contain any \n at the end
=head2 clone
Creates a clone of the current array object and returns it.
Note that this does not clone any element contained inside the array. It only clones the array object itself.
=head2 concat
This method serves to merge two or more arrays. This method does not change the existing arrays, but instead returns a new L<array object|Module::Generic::Array>.
For example:
my $array1 = Module::Generic::Array->new([qw( a b c )]);
my $array2 = [qw( d e f )];
my $array3 = $array1->concat( $array2 );
say @$array3;
# a, b, c, d, e, f
=head2 contains
This is a convenient alias for L</exists>
=head2 delete
Provided with an offset value and an optional length, and this will remove data from the array at the given offset and for the given length.
If no given length is provided, it removes all entries from the offset until the end.
It returns a list of elements removed in list context or a new array object of it in scalar context.
See also L</splice>
=head2 each
Provided with a code reference such as a reference to a subroutine, and this will execute the code passing it the array offset and the current value as the 2 arguements. The current value is also accessible with C<$_>
$a->each(sub
{
print( "I got $_\n" );
# could also write:
# print( "I got $_[1] at offset $_[0]\n" );
});
To exit the loop, return L</break>, for example:
$a->each(sub
{
return( $a->break ) if( $_ eq $not_this_one );
print( "ok, this one\n" );
});
Or you could also return a non-empty false value such as C<0>
=head2 eighth
Returns the corresponding value at the offset position 7 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 empty
This is just an intuitive alias for L</reset>
=head2 error
Returns the value of the global variable C<$ERROR>. However, since this package does not set any error, this does not need to be called, but exists nonetheless for conformity with other packages of this distribution.
=head2 except
Provided with an array reference or an array object, and thi will return a new array object containg all the items that are not in the current array object.
For example:
my $a = Module::Generic::Array->new( [qw( Jack John Paul Peter )] );
my $other = Module::Generic::Array->new( [qw( Emmanuel Gabriel Paul Peter Raphael )] );
my $b = $a->except( $other );
# $b now contains: Jack John
=head2 exists
Provided with a value, including reference, and this returns the number of match, as an L<Module::Generic::Number> object, if it is found in the array, or false otherwise.
=head2 even
Returns a new L<Module::Generic::Array> object of elements whose position in the array are an even number, starting from 0.
For example:
my $a = Module::Generic::Array->new( [qw( 1 2 3 4 5 6 7 8 9 10 )] );
my $even = $a->even;
say "@$even";
Produces: C<1 3 5 7 9>
See also L</odd>
=head2 filter
This filters the array and returns a new array object.
As parameters, it takes a code reference, which is called for each element in the array, and an optional value (typically an object). This code reference is passed 3 arguments:
=over 4
=item 1. the current element, which is also available as C<$_>
=item 2. the element zero-based index position
=item 3. the array object itself
=back
However, if an optional value was supplied, it will be passed to the callback as its first parameter.
The code reference can return a true value to have the element added to the resulting array object, or a false value to have it ignored.
For example:
my $a = Module::Generic::Array->new( [qw( John Jack Peter Gabriel Samuel )] );
my $new = $a->filter(sub{ substr( $_, 0, 1 ) ne 'J' });
# $new now contains only Peter Gabriel Samuel
Or, passing an optional value:
my $new = $a->filter(sub
{
my $self = shift( @_ );
# Do something more with $self
# Then return true or false
substr( $_, 0, 1 ) ne 'J';
}, $self );
See also L</map>
=head2 fifth
Returns the corresponding value at the offset position 4 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 first
Returns the first element of the array, if any.
If there are none and this method is called in an object context, to ensure chaining will work, it will return a L<Module::Generic::Null> object. Otherwise, it will return simply the first element of the array whatever that is.
For example:
# Getting the last_name property from a Person object stored in an array
$a->first->last_name;
Even if there is no such Person object, L</first> will return a L<odule::Generic::Null> object so the call to C<last_name> does not ends up in a perl exception.
But:
my $person = $a->first;
will return whatever is in the first position of the array in non-object context, and in object context if the value is not a reference of any sort, a L<Module::Generic::Scalar> object representing that value. For example:
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->first->length; # 5
# but
say $a->first; # returns "Hello" as a regular string
=head2 for
Provided with a subroutine reference and this will call the subroutine reference, passing it the offset number and the corresponding array value.
$ar->for(sub
{
my( $i, $val ) = @_;
# do something
})
C<$_> is made available and contains the value of C<$val>
It returns the object itself so this can be chained.
To exit the loop, call L</break> or return a defined, but false value such as C<0> or an empty string. You can even return the value returned by calling L</break>. for example:
$a->for(sub
{
# exit now
return( $a->break ) if( $_ eq $not_this_one );
print( "ok, this one\n" );
});
Or you can use L</return>
$a->for(sub
{
if( $_ eq $not_this_one )
{
$a->return( $a->break );
}
else
{
print( "ok, this one\n" );
}
});
In version on or anterior to v1.5.4 you could exit the loop by just returning C<undef>, but since there are unfortunate opportunities for implicit C<undef> being returned, this led to some issues and now it is required to return false, but defined and not empty, such as C<0>.
If you wanted to affect the current offset position relative to the current counter value, you can return a scalar reference containing an integer. For example:
my $a = Module::Generic::Array->new( [qw( Jack John Peter Peter Gabriel Raphael Emmanuel )] );
$a->for(sub
{
my( $i, $name ) = @_;
if( $name eq 'Peter' )
{
$a->splice( $i, 1 );
return( \-1 );
}
# return true
return(1);
});
say "@$a"; # Jack John Gabriel Raphael Emmanuel
And if you wanted to modify the counter value itself, you can change the value of the first argument provided. For example:
$a->for(sub
{
my( $i, $name ) = @_;
if( $name eq 'Peter' )
{
$a->splice( $i, 1 );
$_[0]--;
}
# return true
return(1);
});
say "@$a"; # Jack John Gabriel Raphael Emmanuel
This is useful if you want to modify the array and avoid getting unexpected results.
=head2 foreach
Provided with a subroutine reference and this will call the subroutine reference, passing it the value for each entry in the array.
$ar->foreach(sub
{
my $val = shift( @_ );
# do something
})
It returns the object itself so this can be chained.
P.S. : Do not use L</splice> while using L</foreach>. Perl wanrs you against it in L<perlsync|https://metacpan.org/pod/perlsyn#Foreach-Loops>: "foreach will get very confused if you add or remove elements within the loop body, for example with L</splice>. So don't do that."
Instead use L</for>. See example provided there on how to do it.
C<$_> is made available and contains the value of C<$val>
To exit the loop, call L</break> or return a defined non-empty, but false value such as C<0>. You can even return the value returned by calling L</break>. for example:
$a->foreach(sub
{
# Exit the loop immediately
return( $a->break ) if( $_ eq $not_this_one );
print( "ok, this one\n" );
});
In version on or anterior to v1.5.4 you could exit the loop by just returning C<undef>, but since there are unfortunate opportunities for implicit C<undef> being returned, this led to some issues and now it is required to return false, but defined and non-empty such as C<0>. An empty string would not work.
=head2 fourth
Returns the corresponding value at the offset position 3 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 get
Provided an integer representing an offset and this returns the corresponding value in the array. Offsets start from 0. A blank value will be treated as 0.
my $a = Module::Generic::Array->new( [qw( abc def ghi )] );
$a->get( 1 ); # def
$a->get( '' ); # abc
$a->get( undef() ); # abc
$a->get( -1 ); # ghi
In non-object context, will return the value as is, and in object context and if the value is not a reference of any sort, it returns a L<Module::Generic::Scalar> object representing that value. For example:
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->get(0)->length; # 5
# but
say $a->get(0); # returns "Hello" as a regular string
say $a->get(2); # returns undef
say $a->get(2)->length;
# object context, an Module::Generic::Scalar object is returned
# here 0 would be returned
say $a->get(2)->defined; # false
See also L</index>
=head2 get_null
This operates the same way as L</get>, except that if the value at the offset given is L<perlfunc/undef>, then, instead of returning a L<Module::Generic::Scalar> object representing that value, it will return instead a L<Module::Generic::Null> object.
This works better if you intend to store some objects in the array, and C<undef> went in instead, but you chain the calls expecting a method of that object to return a value. If a L<Module::Generic::Scalar> object were returned, you would end up with undesirable result. With a L<Module::Generic::Null> object, it will silently accepts any chaining methods you pass (it uses AUTOLOAD to do that) and ultimately (when you are out of object context) return C<undef>.
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->get(2)->length; # undef
say $a->get(2)->whatever; # undef
say $a->ge(2)->method1->method2->name; # undef
say $a->get(2); # undef
=head2 grep
# returns a regular list
my( @list ) = $a->grep( 'something' );
my( @list ) = $a->grep( qr/something/ );
my( @list ) = $a->grep(sub
{
/^something$/i;
});
# returns an array object in scalar context
my $list = $a->grep( 'something' );
my $list = $a->grep( qr/something/ );
my $list = $a->grep(sub
{
/^something$/i;
});
# or
my $list = $a->grep(sub
{
my( $val, $index ) = @_;
$val =~ /^something$/i && $index > 2;
});
# get all the elements NOT matching
my $list = $a->grep( 'something', 0 );
my $list = $a->grep( qr/something/, 0 );
my $list = $a->grep(sub
{
/^something$/i;
}, 0);
Provided with some data, and this will do a grep on the array.
If the data provided is a code reference or a reference to a subroutine, the code reference will be called for each array entry, and C<$_> will also be available for each entry. The code reference is passed 2 arguments:
=over 4
=item 1. The current value of the array
=item 2. The index in the array (starting from C<0>)
=back
If the data is a regular expression, each array entry is tested against it.
It takes an optional boolean value, and if false (default), it returns all the entry matching, and if true, it returns all the entry B<not> matching.
It returns a list of matches found in list context and a new L<Module::Generic::Array> in scalar context.
=head2 has
This is an alias for L</exists>
=head2 index
Provided with an index of an element in the array and this returns its corresponding value as is in non-object context, and in object context and if the value is not a reference of any sort, it returns a L<Module::Generic::Scalar> object.
It takes an integer and this ensures the value used is an integer by applying L<perlfunc/int>
my $a = Module::Generic::Array->new( [qw( John Jack Peter )] );
$a->index( 1 ); # returns Jack
And in object context:
say $a->index( 1 )->substr( 0, 2 ); # returns "Ja"
If there is nothing at the given offset, possibly because the array is smaller, then this would return undef in non-object context, or in object context, a L<Module::Generic::Scalar> object representing C<undef()>
=head2 intersection
Provided with an array object, an array reference or a list of elements and this will return a new array object containing all the common elements in both the current array object and the provided list or array reference.
my $intersec1 = [qw( Jack John Paul Peter )];
my $intersec2 = [qw( Emmanuel Gabriel Raphael Peter Michel )];
my $intersec = Module::Generic::Array->new( $intersec1 )->intersection( $intersec2 );
# $intersec now contains 'Peter'
This method basically creates a hash of the current array object and then using L</grep> on the newly provided data, check if any entry exists in the hash and return the result as a new object.
=head2 iterator
This returns a new iterator to cycle through all the array items using iterator's method, such as L<Module::Generic::Iterator/next> and L<Module::Generic::Iterator/prev>. Each iterator element is an L<Module::Generic::Iterator::Element> object
my $i = $a->iterator;
while( $i->has_next )
{
my $elem = $i->next;
my $value = $elem->value;
# Get the next element relative to our element
printf( "Next value is: %s at offset %d\n", $elem->next, $elem->next->pos );
}
=head2 is_empty
Returns L<true|Module::Generic::Boolean/true> if the array is empty, L<false|Module::Generic::Boolean/false> otherwise.
=head2 join
Provided with a string, or expression just as documented in L<perlfunc/"join"> and this will return a string as an L<Module::Generic::Scalar> object.
=head2 keys
my $ar = Module::Generic::Array->new( [qw( Joe John Mary )] );
print $ar->keys->as_string, "\n"; # 0 1 2
This works as documented in L<perlfunc/"keys"> and returns a new L<Module::Generic::Array> object of offset values for each entry in the array.
=head2 last
Returns the last element of the array, whatever that is, in non-object context, and in object context and if the value is not a reference of any sort, it returns a L<Module::Generic::Scalar> object representing that value.
If there are none, instead it will return a L<Module::Generic::Null> to ensure chaining will still work.
For example:
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->last->length; # 5
# but
say $a->last; # returns "world" as a regular string
=head2 length
Returns the size of the array, starting from 1, as a L<Module::Generic::Number> object.
This is different from L</size> that returns value from 0 and -1 if the array is empty.
=head2 list
Returns the array as a list
my $a = Module::Generic::Array->new( [qw( Joe John Mary )] );
print( "@$a" ); # Joe John Mary
my @people = $a->list; # @people now is ( "Joe", "John", "Mary" )
=head2 map
Provided with a reference to a subroutine and this will call the subroutine for each element of the array and return a list in list context or a new L<Module::Generic::Array> otherwise.
For each iteration of the array, C<$_> is made available.
print( $a->map(sub{ $_->value })->join( "\n" ), "\n" );
If you want C<map> to discard a value, your anonymous subroutine must return an empty list, such as:
my $a = Module::Generic::Array->new( [qw( Joe John Mary )] );
my $new = $a->map(sub
{
return if( $_ eq 'John' );
return( $_ );
});
C<$new> will be a L<Module::Generic::Array> object containing only C<Joe> and C<Mary>.
However, do not return C<undef> explicitly in your anonymous subroutine, because perl's C<map> expect an empty list to discard the entry and C<undef> is a not an empty list. So, the following is B<wrong>:
my $a = Module::Generic::Array->new( [qw( Joe John Mary )] );
my $new = $a->map(sub
{
return( undef ) if( $_ eq 'John' );
return( $_ );
});
See also L</filter>
=head2 max
Returns the the element in the array object that has the highest numerical value, as a L<Module::Generic::Scalar> object. For example:
my $values = Module::Generic::Array->new( [qw( 9 5 12 3 7 )] );
my $max = $values->max;
# $max is 12
If the array object, is empty, it will return an L<Module::Generic::Scalar> object representing C<undef>. For example:
my $list = Module::Generic::Array->new;
my $max = $list->max; # $max is undef
$max->defined: # returns false
This method is a wrapper around L<List::Util/max>
=head2 merge
Provided with a list of L<Module::Generic::Array> object and this will merge them with our current one, i.e. the one used to call this L</merge> method.
For example:
my $a = Module::Generic::Array->new( [qw( Jack John Peter )] );
my $b = Module::Generic::Array->new( [qw( Gabriel Raphael Emmanuel )] );
$a->merge( $b );
print( $a->join( ' ' ), "\n" ); # Jack John Peter Gabriel Raphael Emmanuel
Alternatively, you could simply do:
$a->push( $b->list );
Note that this will not discard duplicates, if any. If you want to remove possible duplicates, you could do:
$a->merge( $b )->unique;
=head2 min
Same as L</max>, but returns the the element in the array object that has the lowest numerical value, as a L<Module::Generic::Scalar> object. For example:
my $values = Module::Generic::Array->new( [qw( 9 5 12 3 7 )] );
my $min = $values->max;
# $min is 3
=head2 ninth
Returns the corresponding value at the offset position 8 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 object
Returns the current object. This is useful when chaining to force an object context.
=head2 odd
Returns a new L<Module::Generic::Array> object of elements whose position in the array are an odd number, starting from 0.
For example:
my $a = Module::Generic::Array->new( [qw( 1 2 3 4 5 6 7 8 9 10 )] );
my $odd = $a->odd;
say "@$odd";
Produces: C<2 4 6 8 10>
See also L</even>
=head2 offset
This takes 2 integer as arguments: an offset and optionally a length and it will return a L<Module::Generic::Array> object representing this segment from the current array. Offset starts at 0.
For example:
my $a = $m->new_array( [qw( Jack John Peter Gabriel Raphael Emmanuel )] );
print( $a->offset( 2, 3 )->join( ' ' ), "\n" ); # John Peter Gabriel
Note that the a arguments are converted into an integer, so if you provide a non integer value, it will be turned into one. In this regard, C<undef> would torn into zero.
print( $a->offset( 2, undef )->join( ' ' ), "\n" ); # returns nothing, because length (undef) became 0
If you provide a negative length, it will start back by that much from the offset point up to the offset point.
print( $a->offset( 2, -1 )->join( ' ' ), "\n" ); # John Peter
And if the length is negative, it will start back from the end of the array
print( $a->offset( 2, -3 )->join( ' ' ), "\n" ); # Emmanuel Jack John Peter
The offset itself can be negative and it will position it starting from the end of the array
print( $a->offset( -2, 3 )->join( ' ' ), "\n" ); # Raphael Emmanuel Jack
If only an offset position is provided and no length, it will return all elements from that position until the end of the array:
print( $a->offset(3)->join( ' ' ), "\n" ); # Gabriel Raphael Emmanuel
See L</splice> especially if you want to remove segments of elements from the current array, such as:
print( $a->splice( 1 ) ); # removes and returns John Peter Gabriel Raphael Emmanuel
See L</get> or L</index> if you want to return only one element at a certain offset position.
=head2 pack
my $a = Module::Generic::Array->new( 30..39 );
my $s = $a->pack( 'H2' x 10 );
Like L<perlfunc/pack>, this takes a template and convert the array object. "The resulting string is the concatenation of the converted values."
It returns a new L<Module::Generic::Scalar> object.
See also L<Module::Generic::Scalar/pack>
=head2 pop
In non-object context, it returns the last entry in the array, whatever that is. In object context and if the value is not a reference of any sort, this returns a L<Module::Generic::Scalar> object.
For example:
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->pop->length; # 5
# but
say $a->pop; # returns "world" as a regular string
=head2 pos
Provided with some value (references are ok too), and this will return the position (starting from 0) of it in the array, or undef if nothing was found.
my $a = Module::Generic::Array->new( [qw( John Jack Peter )] );
my $offset = $a->pos( 'Jack' ); # returns 1
$a->pos( 'Bob' ); # Returns undef
my $hash = { first_name => 'John', last_name => 'Doe' };
$a->push( $hash );
$a->pos( $hash ); # Returns 3
Note that it returns the position in the array of the first occurrence found. Maybe I should consider returning a list of all occurrences in list context?
=head2 prepend
This is an alias for L</unshift>
=head2 push
Provided with some data and this adds it at the end of the array.
Note that pushing an L<Module::Generic::Array> object into another L<Module::Generic::Array> object does not actually expand it, because this would imply makin an assumption on what the user actually wants. Thus, you would need to make that clear yourself.
my $a = Module::Generic::Array->new( [qw( John Jack Peter )] );
my $b = Module::Generic::Array->new( [qw( Gabriel Raphael Emmanuel )] );
$a->push( $b );
# Now $a contains something like: John Jack Peter Module::Generic::Array=ARRAY(0x557d2c2983e8)
Instead you might want to do:
$a->push( $b->list );
Or if you prefer:
$a->merge( $b ); # $a now is: John Jack Peter Gabriel Raphael Emmanuel
which will merge array object C<$b> into C<$a>, by pushing all of C<$b>' elements at the end of C<$a>'s stack.
=head2 push_arrayref
Provided with an array reference, and this add all its entry at the end of the array.
my $ar = Module::Generic::Array->new( [qw( John Joe Mary )]);
$ar->push_arrayref( [qw( Jack Peter )] );
print( $ar->join( "," ), "\n" );
# Now prints: John, Joe, Mary, Jack, Peter
=head2 reduce
my $final_value = $array->reduce(sub{ $_[0] + $_[1] });
# or, with an optional initial value
my $final_value = $array->reduce(sub{ $_[0] + $_[1] }, 10);
This is an implementation of the JavaScript C<reduce> equivalent. In that, it is different from the C<reduce> implementation in L<List::Util> that departed from the original JavaScript alter ego.
This method takes a subroutine reference, or an anonymous subroutine as its first parameter, and an optional initial value as its second parameter.
If an initial value was provided, the C<accumulator> value will be set to that initial value and C<reduce> will start iterating from offset C<0>, otherwise, the C<accumulator> value will be set to the first array value, and the iteration will start from offset C<1>.
For each iteration, it will call the callback, in scalar context, with 3 arguments:
=over
=item 1. the current value of the C<accumulator>
=item 2. the value at the current offset
=item 3. the value of the current offset
=back
And C<$_> will be set to the value of the array object at the current position.
The C<accumulator> value gets updated by the return value of each invokation of the callback.
It returns the resulting value of the C<accumulator>
For example:
my $array = Module::Generic::Array->new(0, 1, 2, 3, 4);
my $rv = $array->reduce(sub
{
my( $accumulator, $current_value, $offset ) = @_;
# $current_value is also accessible as $_
return( $accumulator + $current_value );
});
The return value in the above example would be 10.
Since C<reduce> will B<not> skip array index that have an undefined value, you need to be mindful of the definedness of the current value passed, and also that of the C<accumulator>.
my $array = Module::Generic::Array->new;
$array->[0] = 0;
$array->[2] = 1;
$array->[4] = 2;
$array->[6] = 3;
$array->[8] = 4;
As you see, we assigned value in the array object at every other slot, and yet, if we do:
my $rv = $array->reduce(sub
{
my( $accumulator, $current_value, $offset ) = @_;
return( $accumulator ) if( !defined( $current_value ) );
# do something
return( $something_else );
});
If you decided to mutate the C<accumulator> instead of copying it, remember to still return, in the callback, its modified value, or the next iteration will receive whatever was the last value of your callback, which might be C<undef>.
For example:
my $rv = $array->reduce(sub
{
$_[0] += $_[1];
return( $_[0] );
});
Any change, within the callback, to the array object structure, or array values is not recommended as it would lead to unpredictable results and poor code readability just like it would if you did that while using C<foreach>.
Edge cases:
If the array only has one element (regardless of position) and no initial value is provided, or if the initial value is provided but the array is empty, that solo value will be returned without calling the callback.
If an initial value is provided and the array is not empty, then C<reduce> will always invoke the C<callback> starting at offset C<0>.
If an initial value is not provided then C<reduce> will act differently for arrays with length larger than 1, equal to 1 and 0, as shown in the following example:
use POSIX;
my $getMax = sub
{
my( $a, $b ) = @_;
return( POSIX::fmax( $a, $b ) );
};
# callback is invoked for each element in the array starting at offset 0
Module::Generic::Array->new([1, 100])->reduce( $getMax, 50 ); # 100
Module::Generic::Array->new([50])->reduce( $getMax, 10 ); # 50
# callback is invoked once for element at offset 1
Module::Generic::Array->new([1, 100])->reduce( $getMax ); # 100
# callback is not invoked
Module::Generic::Array->new([50])->reduce( $getMax ); # 50
Module::Generic::Array->new([])->reduce( $getMax, 1 ); # 1
Module::Generic::Array->new([])->reduce( $getMax ); # Error, returns undef, or an empty list in list context
Any fatal error occurring in the callback will be caught and an L<error object|Module::Generic::Exception> will be set, and C<undef> will be returned in scalar context, or an empty list in list context.
=head2 remove
This takes an L<Module::Generic::Array> object, or an array reference, or a regular array (i.e. a list) of element and will remove them from the current array object. It works on reference too.
my $dummy = { class => 'Hello' };
my $a = Module::Generic::Array->new( ['Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', 'Raphael', 'Emmanuel'] );
$a->remove( $dummy, qw( John Paul Peter Emmanuel ) );
say( "@$a" ); # Jack Gabriel Raphael
It returns the current object.
=head2 replace
Provided with an old entry and a new one and this will try to find the index position of the old entry, and if found, will replace it with the new one.
=head2 reset
This empty the array, just like L</"undef">
=head2 return
This method is used to send the calling array a return value. It works across multiple embedded loops. For example:
Telling the loop for array C<$a> to terminate while we are in loop for array C<$b>:
$a->for(sub
{
my( $i, $n ) = @_;
$pos = $n;
$b->for(sub
{
my( $j, $v ) = @_;
# Tell loop for array $a to stop
$a->return( undef() ) if( $n == 7 && $v == 27 );
});
# some more stuff here....
});
Telling the loop for array C<$a> to skip 1:
my $a = Module::Generic::Array->new( [qw( Jack John Peter Paul Gabriel Raphael Emmanuel )] );
$a->for(sub
{
my( $i, $n ) = @_;
# tell it to skip Peter
$a->return( +1 ) if( $n eq 'John' );
return( 1 );
});
It works by having the loop for the given array check for a return value assign to it at each iteration. Because it is just a check in an hash, it is very lightweight. When a return value is found, it is reset immediately.
=head2 return_reset
Reset the return value used in methods that implement loop functions.
=head2 reverse
Returns a the array in reverse order in list context or a new L<Module::Generic::Array> object of it in scalar context.
=head2 scalar
Returns the size of the array. It basically calls L</length>
=head2 second
Returns the corresponding value at the offset position 1 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 set
Provided with an array, an array reference or an array-based object and this replaces all the data in the current object by the ones provided.
Note that if an array object is provided, it will copy the content of that object and not set the array object itself.
$a->set( qw( John Jack Peter ) ); # Using an array of elements
$a->set( [qw( John Jack Peter )] ); # Using an array reference of elements
$a->set( $a2 ); # Using another array object, whatever its class may be
=head2 seventh
Returns the corresponding value at the offset position 6 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 shift
Remove the first entry and returns it as is.
In non-object context, it removes the first entry in the array and returns it, whatever that is. In object context and if the value is not a reference of any sort, this returns a L<Module::Generic::Scalar> object.
For example:
my $a = Module::Generic::Array->new( [qw( Hello world )] );
say $a->shift->length; # 5
# but
say $a->shift; # returns "Hello" as a regular string
=head2 sixth
Returns the corresponding value at the offset position 5 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 size
Returns the size of the array starting from 0, and -1 if the array is empty, as a L<Module::Generic::Number> object.
This is equivalent to the perl variable C<$#> as documented in L<perldata>. It returns the last index in the array.
This is different from L</length> that returns value from 1 and 0 if the array is empty.
=head2 sort
Sort the array and return the new array as a list in list context or a new L<Module::Generic::Array> object in scalar context.
If takes an anonymous subroutine or a code reference as an optional argument and if provided, it will be used to sort the data. See L<perlfunc/sort> for more information. This sub will be passed the two elements C<$a> and C<$b> and must return less than, equal to, or greater than 0.
my $new_object = $array->sort;
my @list = $array->sort;
my $new_object = $array->sort(sub{ $_[0] <=> $_[1] });
=head2 splice
Takes the same arguments as the L<perlfunc/"splice"> function, but its return value is different.
If L</splice> is called to add new element, the array object is returned to allow chaining.
If no argument is provided, it just empties the array and the array object is returned to allow chaining.
When only an offset and/or length are provided, it returns the list of elements found as a regular list (not an object) in non-object context. However, In object context, this returns a new L<Module::Generic::Array> object.
For example:
my $a = Module::Generic::Array->new( [qw( I disapprove of what you say, but I will defend to the death your right to say it )] );
say $a->splice( 7, 3 ); # returns a list containing "I", "will", "defend"
say $a->splice( 7 ); # returns a list containing "I", "will", "defend", "to", "the", "death", "your", "right", "to", "say", "it"
But in object context:
say a->splice( 7, 3 )->length; # returns 3 obviously
say a->splice( 7 )->length; # returns 11
Here we use the method "length" but any L<Module::Generic::Array> method workds
=head2 split
Just like the normal L<perlfunc/"split"> function, it takes a string or expression and split the data provided into a list of elements.
It returns the list in list context, and returns a new L<Module::Generic::Array> object in scalar context.
It achieves this by creating a new L<Module::Generic::Scalar> object out of the string given and then calling L<Module::Generic::Scalar/split>
# Using an existing array object
my $a = $ar->split( qr/[[:blank:]\h]+/, "I disapprove of what you say, but I will defend to the death your right to say it" );
$a->length; # 18
# or in list context and using the method as a class method
my @words = Module::Generic::Array->split( qr/[[:blank:]\h]+/, "I disapprove of what you say, but I will defend to the death your right to say it" );
=head2 tenth
Returns the corresponding value at the offset position 9 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 third
Returns the corresponding value at the offset position 2 in the array by calling L</get_null>.
It the caller expects an object in return, such as when chaining methods, and if the value is defined and not a reference of any sort (except scalar), i.e. a regular string, a scalar reference or a scalar object, it is returned as a L<Module::Generic::Scalar> object.
If the value is not defined, or has a zero-length, it is returned as a L<Module::Generic::Null> in object context eseentially to prevent perl error of C<method called on undefined value>, but at the end of the method call chain, will return undef. Under other context, the value is returned as-is,
=head2 unchomp
This does the contrary of L</chomp>, i.e. it adds a new line for each entry in the array.
The meaning of a new line can be set by providing an optional value to L</unchomp>, or by default resorting to the value of C<$/>
It returns the current object.
=head2 undef
Just like L</"reset">, this empty the array.
=head2 unique
Uses L<List::Util> to filter out any duplicates, including reference, and return a new L<Module::Generic::Array> object of the resulting array.
Optionally, you can pass it a true value, and it will update the currently used object instead.
my $dummy = { class => 'Hello' };
my $a = Module::Generic::Array->new( ['Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', $dummy, 'Peter', 'Raphael', 'Emmanuel'] );
my $b = $a->unique;
# $b now contains: 'Jack', 'John', $dummy, 'Paul', 'Peter', 'Gabriel', 'Raphael', 'Emmanuel'
or to update C<$a> directly:
$a->unique(1);
=head2 unshift
This add the given values at the beginning of the array.
=head2 values
Get a list of all the array values and return a list in list context or a ne L<Module::Generic::Array> object in scalar context.
=head1 SERIALISATION
=for Pod::Coverage FREEZE
=for Pod::Coverage STORABLE_freeze
=for Pod::Coverage STORABLE_thaw
=for Pod::Coverage THAW
=for Pod::Coverage TO_JSON
Serialisation by L<CBOR|CBOR::XS>, L<Sereal> and L<Storable::Improved> (or the legacy L<Storable>) is supported by this package. To that effect, the following subroutines are implemented: C<FREEZE>, C<THAW>, C<STORABLE_freeze> and C<STORABLE_thaw>
=head1 SEE ALSO
L<Module::Generic::Scalar>, L<Module::Generic::Number>, L<Module::Generic::Boolean>, L<Module::Generic::Hash>, L<Module::Generic::Dynamic>
=head1 AUTHOR
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
=head1 COPYRIGHT & LICENSE
Copyright (c) 2000-2024 DEGUEST Pte. Ltd.
You can use, copy, modify and redistribute this package and associated
files under the same terms as Perl itself.
=cut