NAME
autobox::Array::Transform - Autobox methods to transform Arrays
DEPRECATION NOTICE!
This module is deprecated, and you should use autobox::Transform instead.
This module will be removed from CPAN and Github, so please switch over right away.
Replace the "use autobox::Array::Transform" statements with "use autobox::Transform".
Now everything should work the same with one exception:
The new group_by default transformation is to put the object as the hash value, not the count.
Where you rely on this, simply replace "group_by" with "group_by_count" and everything should work the same.
SYNOPSIS
# These are equivalent ways to transform arrays and arrayrefs
### map_by
my @genres = map { $_->genre() } @$books;
my @genres = $books->map_by("genre");
my $genres = [ map { $_->genre() } @$books ];
my $genres = $books->map_by("genre");
# With sum from autobox::Core / List::AllUtils
my $book_order_total = sum(
map { $_->price_with_tax($tax_pct) } @{$order->books}
);
my $book_order_total = $order->books
->map_by(price_with_tax => [$tax_pct])->sum;
### grep_by
my $sold_out_books = [ grep { $_->is_sold_out } @$books ];
my $sold_out_books = $books->grep_by("is_sold_out");
my $books_in_library = [ grep { $_->is_in_library($library) } @$books ];
my $books_in_library = $books->grep_by(is_in_library => [$library]);
### group_by
$books->group_by("genre"),
# {
# "Sci-fi" => 3,
# "Fantasy" => 1,
# },
$authors->group_by(publisher_affiliation => ["with"]),
# {
# 'James A. Corey with Orbit' => 1,
# 'Cixin Liu with Head of Zeus' => 1,
# 'Patrick Rothfuss with Gollanz' => 1,
# },
my $genre_books = $books->group_by( "genre", undef, []->gather_sub );
# {
# "Sci-fi" => [ $sf_book_1, $sf_book_2, $sf_book_3 ],
# "Fantasy" => [ $fantasy_book_1 ],
# },
#### flat
my $prolific_author_books = [ map { @{$_->books} } @$authors ]
my $prolific_author_books = $authors->map_by("books")->flat
DESCRIPTION
High level autobox methods you can call on arrays and arrayrefs, e.g. map_by(), grep_by(), group_by()
Raison d'etre
autobox::Core is awesome, for a variety of reasons.
It cuts down on dereferencing punctuation clutter.
It makes map and grep transforms read in the same direction it's executed.
It makes it easier to write those things in a natural order. No need to move the cursor around a lot just to fix dereferencing, order of operations etc.
autobox::Array::Transform provides a few higher level methods for mapping, greping and sorting which are easier to read and write.
Since they are at a slightly higher semantic level, once you know them they also provide a more specific meaning than just "map" or "grep".
(Compare the difference between seeing a "map" and seeing a "foreach" loop. Just seeing the word "map" hints at what type of thing is going on here: transforming a list into another list).
The methods of autobox::Array::Transform are not suitable for all cases, but when used appropriately they will lead to much more clear, succinct and direct code, especially in conjunction with autobox::Core.
Examples
my $total_order_amount = $order->books
->map_by(price_with_tax => [ $tax_pct ])
->sum;
my $order_authors = $order->books
->map_by("author")
->map_by("name")->uniq->sort->join(", ");
List and Scalar Context
All of the methods below are context sensitive, i.e. they return a list in list context and an arrayref in scalar context, just like autobox::Core.
When in doubt, assume they work like map
and grep
, and convert the return value to references where you might have an unobvious list context. E.g.
$self->my_method(
# Wrong, this is list context and wouldn't return an arrayref
books => $books->grep_by("is_published"),
),
$self->my_method(
# Correct, convert the list to an arrayref
books => [ $books->grep_by("is_published") ],
),
$self->my_method(
# Correct, ensure scalar context i.e. an array ref
books => scalar $books->grep_by("is_published"),
),
AUTOBOX ARRAY METHODS
map_by($method, @$args?) : @array | @$array
Call the $method on each item in the list. Like:
map { $_->$method() }
Examples:
my @ahthor_names = $authors->map_by("name");
my $author_names = @publishers->map_by("authors")->map_by("name");
Optionally pass in @$args in the method call. Like:
map { $_->$method(@$args) }
Examples:
my @prices_including_tax = $books->map_by("price_with_tax", [ $tax_pct ]);
my $prices_including_tax = $books->map_by(price_with_tax => [ $tax_pct ]);
grep_by($method, @$args?) : @array | @$array
Call the $method on each item in the list. Like:
grep { $_->$method() }
Examples:
my @prolific_authors = $authors->grep_by("is_prolific");
Optionally pass in @$args in the method call. Like:
grep { $_->$method(@$args) }
Examples:
my @books_to_charge_for = $books->grep_by("price_with_tax", [ $tax_pct ]);
group_by($method, @$args = [], $value_sub = count) : %key_value | %$key_value
Call ->$method(@$args) on each object in the array (just like ->map_by) and group the return values as keys in a hashref.
The default $value_sub gives the count of each value as the values of the hashref.
Example:
my $genre_count = $books->group_by("genre");
# {
# "Sci-fi" => 3,
# "Fantasy" => 1,
# },
The $value_sub
This is a bit tricky to use, so the most common thing would probably be to use canned utility subs which do common things (see below).
The hash key is whatever is returned from $object->$method(@$args).
The hash value is whatever is returned from
my $new_value = $value_sub->($current_value, $object, $key);
where:
$current value is the current hash value for this key (or undef if the first one).
$object is the current item in the list. The current $_ is also set to this.
$key is the key returned by $object->$method(@$args)
[]->gather_sub
This is a utility method to collect all the objects into an array for the hash values. Example:
my $genre_books = $books->group_by( "genre", undef, []->gather_sub );
# keys: genre string
# values: arrayref with the Book objects in $books for each genre string
Note: the undef is to avoid calling "genre" with any arguments.
Note: the slightly weird way of calling []->gather_sub is just a sneaky way to call the gather_sub in the autobox::Array::Transform namespace without exporting anything (the empty array is not actually used for anything).
flat() : @array | @$array
Return a flattened array, assuming the array items themselves are array refs. I.e.
[
[ 1, 2, 3 ],
[ "a", "b" ],
]->flat
returns
[ 1, 2, 3, "a", "b "]
This is useful if e.g. a map_by("some_method") returns arrayrefs of objects which you want to do further method calls on. Example:
# ->books returns an arrayref of Book objects with a ->title
$authors->map_by("books")->flat->map_by("title")
Note: This is different from autobox::Core's ->flatten, which reurns a list rather than an array and therefore can't be used in this way.
DEVELOPMENT
Author
Johan Lindstrom, <johanl [AT] cpan.org>
Source code
https://github.com/jplindstrom/p5-autobox-Array-Transform
Bug reports
Please report any bugs or feature requests on GitHub:
https://github.com/jplindstrom/p5-autobox-Array-Transform/issues.
COPYRIGHT & LICENSE
Copyright 2016- Johan Lindstrom, All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.