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 to 1.

  • The anonymous function returns $state as an element to be used in the array. In the first call this will be 1. 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 value 100. 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.