NAME
Sq::Collection::Array - Array functions
DESCRIPTION
An Sq Array is just a Perl array blessed into the Array package. You could create it yourself by just typing.
my $array = bless([], 'Array');
Nothing is added to the reference or nothing special besides that is done and will never be done. This design is choosen for several reasons.
- Normal Array
-
You always can use and threat an array created by this package like a normal Perl Array. Doing this is completely fine.
my $array = Array->new(1,2,3,4,5); for my $x ( @$array ) { ... } push @$array, 6, 7, 8;
- Compatibility
-
An Sq Array always should and can be used wherever an Array reference is expected. This works as long a library does not do any kind of pseudo type-checking and just uses it as an array reference.
But it also works the other way around. You always can pass a bare Perl Array to any function that expects an array. Consider that this way you obviously cannot use the Method syntax and are forced to use the functional-style.
# works fine my $append = Array::append([1,2,3], [4,5,6]);
- Performance
-
Because an Sq Array is just a normal Perl Array it doesn't have a performance penalty. The only reason why a blessing is added is because the different functions in this package then can be called as a method on an Array.
Most functions you find here is code you would have probably written anyway yourself. So in some way you just can consider this package as a utility library providing you many useful functions that you don't need to write yourself.
It makes developing in itself faster because you don't need to re-implement different functions again and again. Also having functions for common tasks makes code in itself shorter and better understandable leading to fewer bugs in general.
Most functions are written in a style that tries to make the task they do as fast as possible but still with the idea to be as correct and useful as possible.
Using functions from this package can still sometimes makes things a little bit slower when it comes to execution timing because this library heavily depends on passing subroutines and calling them. And calling functions are not free especially in Perl. Every function call has some overhead and sadly Perl has no JIT or inlining capability.
But again, as a Sq Array is just a normal Perl array with an added blessing only for the purpose for calling the function as a method, you always can use a Sq Array like any normal Array and do whatever you want todo with it if the overhead of this module seems to make things slower as expected.
- Convenience
-
This way it just extends the possibility that you can call a lot of functions in this package as methods on an array.
CONSTRUCTORS
Constructor functions are package functions that helps in the creation of new Arrays. All Constructor functions must be called with an arrow ->
as you expect it from typical OO code. Like Array->new(...)
or Array->init(...)
.
Array->new($x,$x,$x,...) : $array
Creates an Array with the specified values to new
. There is a special behaviour that aborts on an undef
. This is to be align with the Sq::Collections::Seq data-structure that uses undef
to abort a sequence. But you anyway don't want to have undef
as values in an array.
my $numbers = Array->new(1,2,3,4,5); # [1..5]
my $numbers = Array->new(1,2,3,undef,4,5,6) # [1,2,3]
Array->wrap($x,$y,$z,...) : $array
Same as new
. Used this naming because of the Monad Abstraction. Maybe get deleted.
Array->empty : $array
Returns a new empty Array.
my $empty = Array->empty;
Array->bless($array) : $array
Adds the Array blessing to the array reference and returns it. Can be used in two ways.
my $someArray = [1,2,3];
Array->bless($someArray);
my $someArray = Array->bless([1,2,3]);
Array->from_array($array) : $array
Same as Array->bless
Array->replicate($count, $value) : $array
Creates a new Array that contains $value
$count
times.
my $xs = Array->replicate(5,"x"); # [qw/x x x x x/]
Array->range($start, $stop) : $array
Generates a new array from $start
to $stop
inclusive. It also supports counting downwards. $start
and $stop
are converted to int before function starts. When you need floating values use range_step
instead.
my $array = Array->range(1,10); # [1..10]
my $array = Array->range(10,1); # [10,9,8,7,6,5,4,3,2,1]
Array->range_step($start, $step, $stop) : $array
Like Array->range
but let's you specify a step. Both values are inclusive and also supports steps with floating-point. Consider floating-point inaccurassy.
my $array = Array->range(1,2,10) # [1,3,5,7,9]
my $array = Array->range(10,2,1) # [10,8,6,4,2]
my $array = Array->range(1,0.2,2) # [1,1.2,1.4,1.6,1.8,2]
my $array = Array->range(1,0.2,2) # [2,1.8,1.6,1.4,1.2,1]
Array->concat(@arrays) : $array
Returns a new array with all arrays concatenated into a new one.
# [1,2,3,4,5,6,7,10,10,10]
my $array = Array->concat(
[1,2,3,4],
Array->new(5,6,7),
Array->replicate(3, 10),
)
# same as
my $array = Array->range(1,7)->append([10,10,10]);
Array->init($count, $f_x) : $array_x
Generates a new Array
with $count
entries. An entry generating function $f_x
is called by passing it the current index. The function can return multiple values as a list and they will become one list, theoretically exceeding $count
. undef
values are skipped.
my $array = Array->init(5, sub($idx) { $idx }); # [0,1,2,3,4]
my $array = Array->init(5, sub($idx) { "1" x $idx }); # ["","1","11","111","1111"]
my $array = Array->init(3, sub($idx) { +{$idx => 1} }); # [{0 => 1},{1 => 1},{2 => 1}]
my $array = Array->init(3, sub($idx) { 1, 1 }); # [1,1,1,1,1,1]
my $array = Array->init(3, sub($idx) { 1, undef }); # [1,1,1]
Array->unfold($state, $f_opt_x_state) : $array_x
Generates a new Array by passing the function $f_opt_x_state
the $state
. $f_opt_x_state
must return either an optional value containing [$x,$state]
where $x
is the value to be used and $state
the next state to be used.
Instead of an optional you also can return the values in list context. Then the empty list or the return of undef
is used to indicate the None case and this abortion of creation of new values. See Option->extract_array()
for further details.
# [1..99]
my $array = Array->unfold(1, sub($state) {
if ( $state < 100 ) { return Some([$state, $state+1]) }
else { return None }
});
# [1..99]
my $array = Array->unfold(1, sub($state) {
if ( $state < 100 ) { return $state, $state+1 }
else { return }
});
# [1..99]
my $array = Array->unfold(1, sub($state) {
if ( $state < 100 ) { return $state, $state+1 }
else { return undef }
});
All cases generates an array containing the numbers from 1 to 99. It works the following.
The anonymous function is called with the starting
$state
that was set to1
.The anonymous function returns
$state
as an element to be used in the array. In the first call this will be1
. The next state for the next call to the anonymous function is set to$state + 1
.The anonymous function is called with
2
as this was the next state that should be used.This process keeps going on until at some point
$state
reaches the value100
. At this$state
the anonymous function returns nothing and the generation of the array is aborted.
unfold
is a very powerful function. Theoretically all constructor functions can be implemented by unfold
. Everytime you use some kind of loop to generate a new array, you can potentially replace it by an unfold
. This is the functional way to generate data without relying on mutation of any variables.
# [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987]
my $array =
Array->concat(
[1,1],
Array->unfold([1,1], sub($state) {
# $state starts with [1,1]
my ($x,$y) = @$state;
my $next_fib = $x + $y;
if ( $next_fib < 1000 ) {
return $next_fib, [$y,$next_fib];
}
return;
})
);
this code roughly translates to
my $array = [1,1];
my $state = [1,1];
while (1) {
my ($x,$y) = @$state;
my $next_fib = $x + $y;
if ( $next_fib < 1000 ) {
push @$array, $next_fib;
$state = [$y,$next_fib];
next;
}
last;
}
METHODS
All methods can be called as a method on an Array
(hence the name method), but calling every method in a functional-style is also supported and not discouraged. Every method listed here returns a new array as a result and does no mutation.
As a Perl developer you should know that calling
$array->method($x, $y);
is the same as
Array::method($array, $x, $y);
usually calling it in the second form is discouraged because it doesn't work properly with inheritance. But inheritance is anyway not supported by this module and instead inheritance is highly discouraged. You do something horrible wrong if for whatever reason you want to have inheritance.
Calling it in the functional interface form also has another benefit that it also works with unblessed array references. This module was written from the ground up to support both styles and also to work with any unblessed array reference.
By default you obviously cannot write.
[1..10]->append([11..20])
because [1..10]
is just a perl array reference and has no blessing added to the Array
module. You either must create [1..10]
with some constructor methods like Array->new(1..10)
or Array->range(1,10)
or add the blessing with Array->bless
or you just use the functional interface.
# All arrays represent an array [1..20]
my $array = Array::append([1..10], [11..20])
my $array = Array->range(1,10)->append([11..20])
my $array = Array->range(1,10)->append(Array->range(11,20))
my $array = Array->new(1..10)->append([11..20])
But whatever you do. All methods will always return a blessed Array
reference. So you always can chain methods even if you started without any.
my $array = Array::append([1..10], [11..20])->rev # Array->range(20,1)
copy($array) : $array
Creates a shallow copy of an array, up until the first undef
. This behaviour is choosen to avoid undef
in data and also being consisten to the Seq
data-structure that uses undef
for aborting a sequence. Also Array->unfold
uses undef
for aborting and other function expectin optional values.
# both are [1,2,3]
my $copy = Array::copy([1,2,3]);
my $copy = Array::copy([1,2,3,undef,4,5,6]);
append($array1, $array2) : $array
returns a $new array that has $array2 appended onto $array1. append
only works with two arrays (one argument in method-style). If you want to append multiple arrays together use Array->concat
instead.
my $array = Array->range(1,3)->append([4,5,6])->append([7,8,9]) # [1..9]
my $array = Array->concat(
[1..3],
[4,5,6],
Array->range(7,9),
);
rev($array) : $array
returns a new array with all elements reversed
# [5,4,3,2,1]
my $array = Array->range(1,5)->rev
bind($array_a, $f_array_b) : $array_b
Iterates through each element of an array and passes each element to the function $f_array_b
. $f_array_b
must then return another array. The results of all function calls are then concatenated into a single array.
When you pass the same function $f_array_b
to map
and then flatten
you achieve the same result as calling bind
.
my $words = Array->new(qw/foo bar baz/);
# [qw/f o o b a r b a z/]
my $chars =
$words->bind(sub($word) {
return [split //, $word];
});
flatten($array_of_array) : $array
Flattens an array of an array into a single array.
# [qw/f o o b a r b a z/]
my $chars = Array->new([qw/f o o/], [qw/b a r/], [qw/b a z/])->flatten;
# [qw/f o o b a r b a z/]
my $chars = Array::flatten([
[qw/f o o/],
[qw/b a r/],
[qw/b a z/],
]);
# [qw/f o o b a r b a z/]
my $chars =
Array->new(qw/foo bar baz/)
->map(sub($word) { [split //, $word] })
->flatten;
cartesian($arrayA, $arrayB) : $array_of_array_a_b
returns a new array containing the cartesian product of both arrays. The cartesian product is every item in $arrayA
combined with every item in $arrayB
.
# manually creating cartesian product of two arrays
my @cartesian;
for my $a ( @as ) {
for my $b ( @bs ) {
push @cartesian, [$a, $b];
}
}
# cartesian product of two arrays
$as->cartesian($bs)->iter(sub($pair) {
my ($a, $b) = @$pair;
printf "A=%s B=%s\n", $a, $b;
});
map($array, $f_map) : $array
Similar to Perl built-in map
. But with few changes.
Expects
$f_map
to return a single value instead of a list.Passes the current value as an argument to the function.
Aborts when
undef
is returned.
# [1, 4, 9, 16, 25]
my $squared = Array->range(1,5)->map(sub($x) { $x * $x });
my $squared = Array->range(1,5)->map(sub { $_ * $_ }); # 20% faster
These changes are made for compatibility with the Seq
data-structure. When you use this function instead of map { ... } @array
then you can switch to Seq
or other data-structures supporting a map
without further changes.
These changes makes Array::map
slower compared to perl built-in map
but gives you the flexibility to switch data-structure more easily. On the other side I could have re-implemented the whole map
logic in Seq::map
but that would have made Seq::map
very slow and hard to implement and isn't really worth it because instead of one functions that does $number things, we have $number functions instead.
my %hash = map { $_ => 1 } @array;
my $hash = $array->count;
my %hash = map { function($_) => 1 } @array;
my $hash = $array->count_by(\&function);
my %hash = map { key($_), value($_) } @array;
my $hash = $array->to_hash(sub($x) {
return key($x), value($x);
});
my @array = map { $_ > 10 ? $x : () } @array;
my $array = $array->choose(sub($x) { $x > 10 ? Some($x) : None });
Because Array::map
aborts on undef
it now allows too early exit processing of an Array that is not possible with map { ... } @array
.
# [1,4,9,16]
my $array = Array->range(1,10)->map(sub($x) { $x < 5 ? $x*$x : undef })
Instead of using perl built-in map
consider if another method does not fit your use-case better. Otherwise you always can use map { ... } @array
. Never forget that this whole Module is an optional addition and you always can threat an Array
as a perl array. But you will lose some flexibility when you do.
map_e($array, $expr) : $array
This is the same as Array::map
but uses string-eval to build the final code. Why string-eval? It is the fastest solution because it avoids calling a lambda. When using this version you must use $_
in your string.
Array->range(1,1000)->map_e( '$_ < 10 ? $_*2 : undef' ); # 100% faster
Array->range(1,1000)->map(sub { $_ < 10 ? $_*2 : undef });
mapi($array_a, $f_b) : $array_b
Same as map
but the function $f_b
additionally gets an index passed. You also can use $_
to access the current value, and undef
also aborts the creation of the new array.
# [[0,"foo"], [1,"bar"], [2,"baz"]]
my $array =
Array->new(qw/foo bar baz/)
->mapi(sub($x,$i) { [$i,$x] };
choose($array, $f_opt) : $array
choose
combines map
and filter
in a single operation. Every value of $array
is passed to $f_opt
. $f_opt
is supposed to return an optional value. When it is Some value than this value is added to the newly returned array. None values are skipped.
my $data = Array->range(1,10);
# [4,16,36,64,100]
my $evens_squared = $data->choose(sub($x) {
$x % 2 == 0 ? Some($x * $x) : None
});
# [4,16,36,64,100]
my $evens_squared = $data->choose(sub($x) {
$x % 2 == 0 ? $x * $x : undef
});
# [4,16,36,64,100]
my $evens_squared = $data->choose(sub($x) {
$x % 2 == 0 ? $x * $x : ()
});
# [4,16,36,64,100]
my $evens_squared =
$data
->filter(sub($x) { $x % 2 == 0 });
->map( sub($x) { $x * $x })
filter($array, $predicate) : $array
Iterates through each element of an array and passes it to the $predicate
function. When the $predicate
function returns a truish value then the value is returned in a new array. Works like the perl built-in grep
.
# [2,4,6,8,10]
my $evens = Array->range(1,10)->filter(sub($x) { $x % 2 == 0 });
filter_e($array, $expr) : $array
Same as filter
but expects a string as $expr
. It uses string-eval to build the final filtering instead of calling a lamda function. This overall results into a big performance boost. You must use $_
in $expr
to acces the current value. Has the same performance as a manual grep
call.
my $evens = Array->range(1,10)->filter_e( '$_ % 2 == 0'); # 250% faster
my $evens = Array->range(1,10)->filter(sub($x) { $x % 2 == 0 });
skip($array, $amount) : $array
skips $amount
entries of an array. Negative values or zero has no effect. Skipping more elements than the array has leds to an empty array. Always returns a new array, even in the case of passing it a zero or negative amount.
# [6,7,8,9,10]
my $array = Array->range(1,10)->skip(5);
# [1..10]
my $array = Array->range(1,10)->skip(-10);
# []
my $array = Array->range(1,10)->skip(100);
take($array, $amount) : $array
Takes the first $amount
elements of an array and returns it as a new array. zero or negative elements return an empty array. Taking more elements as the array just returns the whole array again. Always returns a new array.
# [1,2,3,4,5]
my $five = Array->range(1,100)->take(5);
indexed($array) : [[$x,$index], [$x,$index], ...]
Returns a new array where each element is put together with its index inside another array. Consider using mapi
or iteri
if they are more appropiated for whatever you wanna do.
# [[5,0], [6,1], [7,2], [8,3], [9,4], [10,5]]
my $array = Array->range(5,10)->indexed;
zip($arrayA, $arrayB) : $array_of_tuple
Iterates through both arrays at the same time. Always puts the same index elements from both arrays into a tuple. When $arrayA
and $arrayB
are of different size then only iterates for the shortest length array. Also stops when an undef
is encountered somewhere.
# [[1,'a'], [2,'b'], [3,'c']]
my $array_of_tuple = Array::zip(
[1 .. 10],
['a' .. 'c']
);
The word tuple is just used for clarification what it does. A tuple here is just an Array and is also blessed in the Array
package.
sort($array, $comparer) : $array
Sorts an Array. Basically the same as just calling built-in sort
but passes two values of the array to the $comparer
function instead of using global variables $a,$b
.
my $sorted = sq([10,3,11,4,10])->sort(sub($x,$y) { $x <=> $y });
sort_by($array, $comparer, $f_key) : $array
Does a Schwartzian Transformation. It first computes all keys by passing every element of $array
to $f_key
. Then it uses those keys in combination with $comparer
to sort the array. Then it throws the key away and gives you the sorted list back.
The additional step of computing the key once makes it faster, because otherwise $f_key
would be called O(log n) times for every key. It comes at the expense of using more memory.
my $data = sq [
{ id => 2, name => 'Frank' },
{ id => 1, name => 'Anne' },
{ id => 3, name => 'Zander' },
];
my $id_sorted = $data->sort_by(sub($x,$y) { $x <=> $y }, key 'id');
my $name_sorted = $data->sort_by(sub($x,$y) { $x cmp $y }, key 'name');
# Pure Perl Version of id sorted
my @id_sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, $_->{id} ] }
@$data;
sort_num($array) : $array
Sorts an array by number.
my $sorted = Array->new(6,4,2,10)->sort_num; # [2,4,6,10]
sort_str($array) : $array
Sorts an array by strings.
my $sorted = Array->new(qw/c a b/)->sort_str; # [qw/a b c/]
sort_hash_str($array, $key) : $array
Sorts an array of hashes by selecting which key should be used for sorting. Values are string compared.
my $data = Array->new(
{id => 3, name => "foo"},
{id => 1, name => "bar"},
{id => 2, name => "alf"},
);
my $sorted = $data->sort_hash_str('name');
# [
# {id => 2, name => "alf"},
# {id => 1, name => "bar"},
# {id => 3, name => "foo"},
# ];
sort_hash_num($array, $key) : $array
Sorts an array of hashes by selecting which key should be used for sorting. Values are number compared.
my $data = Array->new(
{id => 3, name => "foo"},
{id => 1, name => "bar"},
{id => 2, name => "alf"},
);
my $sorted = $data->sort_hash_str('id');
# [
# {id => 1, name => "bar"},
# {id => 2, name => "alf"},
# {id => 3, name => "foo"},
# ];
fsts($array_of_array) : $array
returns a new array by just selection the first elements of the inner array.
my $data = Array->new(
[1,2],
[3,4],
[5,6],
);
my $array = $data->fsts; # [1,3,5]
snds($array_of_array) : $array
returns a new array by just selection the second elements of the inner array.
my $data = Array->new(
[1,2],
[3,4],
[5,6],
);
my $array = $data->snds; # [2,4,6]
to_array($array, $count=undef) : $array
This function primarily exists because of API compatibility with Seq
and List
. But because of the optional argument $count
its behaviour depends on that argument. It's behavior is choosen to have zero-impact on performance when it is possible.
When $count
is not passed or is undef
than the $array
is just returned as-is without doing anything. This means you easily can change from Seq
or List
to Array
and for example do benchmarks without caring much about a to_array
call creating a copy.
But when $count
is being passed than a new Array is maybe created. When $count
is smaller or equal to 0
than a new empty array is returned. Otherwise $count
elements are copied to a new array, expect when $count
is greater than the original array, than again $array
is just being returned as-is.
my $data = Array->range(1,100);
my $array = $data->to_array(); # noop: my $array = $data;
my $array = $data->to_array(0); # []
my $array = $data->to_array(-1); # []
my $array = $data->to_array(10); # [1..10]
my $array = $data->to_array(1000); # noop: my $array = $data;
If you really want to create a copy of an Array use copy
. If you want to extract a portion of an array into a new Array use slice
.
to_array_of_array($array_of_array) : $array_of_array
Does nothing. Only here because of API compaitbility with $seq->to_array_of_array
. Also does no type-checking if you passed in an array of array.
distinct($array) : $array
Returns an array with distinct values. Only works properly when array entries can be turned into strings. Under the hood a hash is used to keep track of seen values.
If used on objects other than string or numbers it will properly not work correctly unless a string overload is defined. In those cases use distinct_by
.
my $array = Array->new(1,2,1,"foo",3,2,"bar")->distinct; # [1,2,"foo",3,"bar"]
distinct_by($array, $f_str) : $array
Returns an array with distinct values. A Hash is used to keep track of seen values. Every value is passed to $f_str
to compute the string used in the hash of seen values.
my $data = Array->new(
{id => 1, name => "foo"},
{id => 3, name => "foo"},
{id => 1, name => "bar"},
{id => 2, name => "bar"},
);
my $array = $data->distinct_by(key 'id');
# [
# {id => 1, name => "foo"},
# {id => 3, name => "foo"},
# {id => 2, name => "bar"},
# ]
my $array = $data->distinct_by(key 'name');
# [
# {id => 1, name => "foo"},
# {id => 1, name => "bar"},
# ]
regex_match($array, $regex, $picks) : $array
TODO
windowed($array, $window_size) : $array
TODO
intersperse($array, $value) : $array
TODO
repeat($array, $count) : $array
TODO
take_while($array, $predicate) : $array
TODO
skip_while($array, $predicate) : $array
TODO
slice($array, @idxs) : $array
Similar to an Array slice in Perl. But indexes that are out-of-bound don't return an undef
value, they are just skipped.
my $array = Array->range(0,10);
my $slice = $array->slice(-1,20,0,5,-20); # [10,0,5]
my @slice = $array->@[-1,20,0,5,20,-20]; # (10,undef,0,5,undef)
extract($array, $pos, $length) : $array
Extracts a portion of values into a new array. The values are a shallow copy, but the array is a new array. If $pos
is negative than it is considered as a position from the end. $length
says how much elements starting from $pos
should be extracted. If $length
is zero or negative a new empty array is returned. It only extracts or creates as much values the original array can provide.
my $data = Array->range(1,10);
$data->slice(0,3) # [1,2,3]
$data->slice(1,3) # [2,3,4]
$data->slice(20,10) # []
$data->slice(5,100) # [6,7,8,9,10]
$data->slice(3,3) # [4,5,6]
$data->slice(9,1) # [10]
$data->slice(0,0) # []
$data->slice(0,-10) # []
$data->slice(-3,3) # [8,9,10]
CONVERTER
Converter are methods on an array that don't return Array
.
length($array) : $int
Returns the amount of elements in an array.
my $count = Array->new(0,0,0)->length; # 3
fold($array, $state, $f_state) : $state
Iterates through each element of an array. On first iteration it passes the first element and state $x,$state
to the function $f_state
. $f_state
then returns the next state that is used in the next call to $f_state
and the next item of the array. This continues until all elements of an array are iterated. The last state of the last $f_state
function call is returned.
When $array
is empty $state
is immediately returned.
# 55
my $sum = Array->range(1,10)->fold(0, sub($x,$state) { $state + $x });
fold_mut($array, $state, $f) : $state
Same as fold
but it the function $f
is not supposed to return the new $state
. This function assumes that $state
is a mutable variable, for example an array, hash and so on that is mutated on every invocation. Once all elements are iterated $state
is returned. When $array
is empty than $state
is immediately returned.
This version is usually faster when we build something through mutation.
# this basically creates a copy of "Array->range(1,10)"
my $array = Array->range(1,10)->fold(Array->new, sub($x,$array) {
$array->push($x)
});
This is basically what fold_mut
looks like in pure perl.
my $array = [];
for my $x ( 1 .. 10 ) {
push @$array, $x;
}
return $array;
reduce($array, $f_x) : $opt_x
The idea is to combine two values into one value. Two values are passed to $f_x
that combines the value into a new one. That new value is then passed with the third value of an array. Continues until all values are iterated and the last call to $f_x
is returned. When the array only has one value than this value is returned without $f_x
is ever being called. When the array is empty None
is returned.
reduce
is a lot like fold
. reduce
just omits the starting state, the idea usually is to combine something of the same type into just one value of the same type. But through the dynamic-typing nature of Perl we usually can exploit this behaviour and return something of any type.
A problem of reduce
is when the Array is empty. Because then it is unknown which value should be returned. Because of this reduce
returns an optional.
When you always want a value and not an optional you should use fold
instead.
my $opt = Array->range(1,10)->reduce(sub($x,$y) { $x + $y }); # Some(55)
my $opt = Array->empty ->reduce(sub($x,$y) { $x + $y }); # None
expand($array) : ($x,$x,$x,$x,...)
Expands an array into its values. Array is just an array-reference. Calling expand
is the same as writing @$array
.
# all are the same
for my $x ( $array->expand ) { ... }
for my $x ( $array->@* ) { ... }
for my $x ( @$array ) { ... }
first($array) : $opt
Returns the first element of an array as an optional. Returns None
if the Array is empty.
my $opt = Array->range(1,10)->rev->first; # Some(10)
my $opt = Array->empty->first; # None
my $opt = Array->empty->first->or(100); # 100
last($array) : $opt
Returns the last element of an array as an optional. Returns None
if the Array is empty.
my $opt = Array->empty->last; # None
my $opt = Array->range(1,10)->last; # Some(10)
my $opt = Array->range(1,10)->rev->last->or(0); # 1
sum($array_of_numbers) : $number
Adds all numbers together in an array. Does no type-checking or something like that. If you have an array with other values than numbers then expect a lot of warnings and weird results.
# 55
my $sum = Array->range(1,10)->sum;
sum_by($array, $f_map) : $number
A lot like sum
but every value of an array is first passed to the function $f_map
. That function then should return a number that is used for adding. You could achive the same by calling $array->map($f_map)->sum
but this version is faster because it doesn't need to create an intermediate array.
my $value = sub($hash) { $hash->{value} };
my $data = Array->new(
{id => 1, value => 5 },
{id => 2, value => 3 },
{id => 3, value => 7 },
);
# 15
my $sum = $data->sum_by($value);
# 15
my $sum = $data->map($value)->sum;
join($array_of_str, $sep) : $string
concatenates an array of strings into a single string. The same as the perl built-in function join
.
# "1,2,3,4,5,6,7,8,9,10"
my $str = Array->range(1,10)->join(',');
split($array_of_str, $regex) : $array_of_array_string
performs a split
operation on every string in the array. This then returns an array of arrays containing string. Every inner array is also a blessed Sq Array.
You could achieve the same by using map
and then splitting every string. But this version is faster.
# [[1,2,3], [4,5,6]]
my $data = Array->new("1-2-3", "4-5-6")->split(qr/-/);
# same as
my $data = Array->new("1-2-3", "4-5-6")->map(sub($str) {
Array->new(split /-/, $str)
});
min($array_x) : $opt_x
TODO
min_by($array_x, $f_number) : $opt_x
TODO
min_str($array_x) : $opt_x
TODO
min_str_by($array_x, $f_str) : $opt_x
TODO
max($array_x) : $opt_x
TODO
max_by($array_x, $f_number) : $opt_x
TODO
max_str($array_x) : $opt_x
TODO
max_str_by($array_x, $f_str) : $opt_x
TODO
group_fold
TODO
to_hash($array, $mapper) : $hash
Applies $mapper
function to each Array entry that return the new Key,Value to be used in a Hash. When you return a Key that was already computed before you will overwrite the previous value.
# { 3 => "bar", 5 => "world", 1 => "a" }
my $hash = Array->new(qw/foo bar hello world a/)->to_hash(sub($x) {
length($x) => $x
});
# the above can be translated to
my $hash = {};
for my $x ( qw/foo bar hello world a/ ) {
$hash->{ length $x } = $x;
}
to_hash_of_array($array, $mapper) : $hash_of_arrays
Same as to_hash
but instead of overwriting previous values it collects all values of the same key into an array.
# { 3 => ["foo","bar"], 5 => ["hello", "world"], 1 => ["a"] }
my $hash = Array->new(qw/foo bar hello world a/)->to_hash_of_array(sub($x) {
length($x) => $x
});
# the above can be translated to
my $hash = {};
for my $x ( qw/foo bar hello world a/ ) {
push $hash->{ length $x }->@*, $x;
}
as_hash($array) : $hash
Transforms array into an hash. Same as assigning Array to a Hash. But blessed in the Hash
package and as a reference.
my %hash = @$array;
my $hash = $array->as_hash;
keyed_by($array, $f_key) : $hash
TODO
group_by($array, $f_key) : $hash
TODO
count($array) : $hash
TODO
count_by($array, $f_key) : $hash
TODO
find($array, $predicate) : $opt
Iterates through every element of $array
and passes the value to $predicate
. When this function returns a truish value it will return the first found value as Some value. When no value could be found it returns None.
my $opt = Array->range(1,10)->find(sub($x) { $x > 5 }); # Some(6)
my $opt = Array->range(1,10)->find(sub($x) { $x > 20 }); # None
any($array, $predicate) : $bool
Checks if any value in $array
satisfies a predicate.
my $bool = Array->range(1,10)->any(sub($x) { $x > 5 }); # 1
my $bool = Array->range(1,10)->any(sub($x) { $x > 100 }); # 0
all($array, $predicate) : $bool
Checks if all values in $array
satisfies a predicate.
my $bool = Array->range(1,10)->all(sub($x) { $x > 0 }); # 1
my $bool = Array->range(1,10)->all(sub($x) { $x < 9 }); # 0
none($array, $predicate) : $bool
Checks if no value in $array
satisfies a predicate.
my $bool = Array->range(1,10)->none(sub($x) { $x < 0 }); # 1
my $bool = Array->range(1,10)->none(sub($x) { $x > 9 }); # 0
pick($array, $f_opt) : $opt
pick
is like find
and map
in one operation. Every item in the array is passed to $f_opt
. When $f_opt
returns Some value then this value is returned as an optional. When $f_opt
returned None for every value then None is returned.
my $opt = $array->pick(sub($x) { $x > 100 ? Some($x*$x) : None });
my $r = Array->range(1,10);
my $opt = $r->pick(sub($x) { $x > 5 ? Some($x*$x) : None }); # Some(36)
my $opt = $r->pick(sub($x) { $x > 10 ? Some($x*$x) : None }); # None
my $x = $r->pick(sub($x) { $x > 10 ? Some($x*$x) : None })->or(100); # 100
# you also can return normal values/undef
my $opt = $r->pick(sub($x) { $x > 5 ? $x*$x : undef }); # Some(36)
my $opt = $r->pick(sub($x) { $x > 5 ? $x*$x : () }); # Some(36)
to_seq($array) : $seq
Transform an array into a sequence. Same as calling Seq->from_array($array)
but does it in a chain.
my $seq = Array->range(1,10)->to_seq;
dump($array, $inline=60, $depth=0) : $str
Recursivly traverses data-structures and creates a human readable dump from it.
$inline
controls the amount of characters a data-structure is completely inlined into a single string without newlines. The higher the number the more compact your dump will be.
It currently has a bug as it also collaps whitespace in a string and it shouldn't do that. This could be avoided by setting $inline
to 0
. But consider that dumping in its current form is considered for debugging purposes, not for serializing data.
Currently it is not perfect. It only works with Perl Array/Hash and Sq Array/Hash and the Option type. Sq Array/Hash are just dumped as normal Perl Array/Hash. No other object is being dumped. It also does not dump any other object and has no configuration. Also doesn't detect cyclic data-structures. But for most practical data-structures it works good enough at the moment. Get's improved in the future.
printf "%s\n", $array->dump;
dumpw($array, $inline=60, $depth=0) : void
Same as dump
but instead of returning the dump as a string, automatically prints it using warn
.
$array->dumpw;
warn $array->dump, "\n";
MUTATION
The following methods mutate the array instead of creating a new one.
push($array, @values) : void
Adds elements to the end of the array. Like the built-in push
function but additionally stops at first undef
. If you want to push undef
into an array then use the perl built-in push @$array, undef
.
my $array = Array->new;
$array->push(1,2,3); # $array = [1,2,3]
$array->push(4,undef,5) # $array = [1,2,3,4]
pop($array) : $x
Removes the last element from the array and returns it. Same as perl built-in pop
my $last = $array->pop;
shift($array) : $x
Removes the first element from the array and returns it. Same as perl built-in shift
my $first = $array->shift;
unshift($array, @values) : void
Adds elements to the front of an array. Same as perl built-in unshift
but stops at first undef
. If you still want to unshift undef to the array use the perl built-in sunhift @$array, undef
.
my $array = Array->new(1,2,3,4,5);
$array->unshift(qw/a b c/); # ['a','b','c',1,2,3,4,5]
$array->unshift('d', 'e', undef, 'f'); # ['d','e','a','b','c',1,2,3,4,5]
blit($source_array, $source_index, $target_array, $target_index, $count) : void
Copies $count
entries from $source_array
at position $source_index
to $target_array
starting at position $target_index
.
$source_index
and $target_index
can both be negative indexes to define an index from the end.
Only copies as much values that are present in $source_array
.
my $source = Array->range(100,105);
my $target = Array->range(1,5);
$source->blit(0, $target, 0, 3); # $target -> [100,101,102,4,5]
$source->blit(-2, $target, 0, 100); # $target -> [104,105,102,4,5]
$source->blit(4, $target, -3, 2); # $target -> [104,105,104,105,5]
$source->blit(0, $target, -1, 100); # $target -> [104,105,104,105,100,101,102,103,104,105]
shuffle($array) : void
Randomly shuffles array in-place;
my $array = Array->range(1,10);
$array->shuffle; # values now in random order
SIDE-Effects
The following methods have no return value and exists for various kind of doing side-effects.
iter($array, $f) : void
Iterates through an array and passes each element to the provided function that does some kind of side-effect.
# prints all numbers from 1 to 100
Array->range(1,100)->iter(sub($x) { say $x });
iteri($array, $f) : void
Iterates through an array and passes each element inlcuding the index to the provided function that does some kind of side-effect.
# prints: 0 => 1, 1 => 2, 2 => 3 ...
Array->range(1,100)->iter(sub($x,$i) { printf "%d => %d\n", $i, $x });
foreach($array, $f) : void
Same as iter
, just an alias.
foreachi($array, $f) : void
Same as iteri
, just an alias.