Array-GroupBy

 view release on metacpan or  search on metacpan

lib/Array/GroupBy.pm  view on Meta::CPAN

that maximum salary.

  use Array::GroupBy;
  use List::Util qw( max );

  # salary dataset
  my @amounts = (
      [ "Smith, J", 2009, 65 ],
      [ "Smith, J", 2010, 63 ],
        ...
      [ "Brown, F", 2006, 45 ],
      [ "Brown, F", 2007, 47 ],
        ...
  );

  my $iter = igroup_by(
                data    => \@amounts,
                compare => sub { $_[0]->[0] eq $_[1]->[0] },
                      );

  while (my $subset = $iter->()) {
    my $max_sal = max map { $_->[2] } @$subset; # max salary

    print "Name: $subset->[0]->[0], ",
           "Max Salary: $max_sal, Year(s) max salary reached: ",
           join(', ',
               map  { $_->[1] }
               grep { $_->[2] == $max_sal } @$subset
           ),
           "\n";
  }

See C<t/5.t> for code.

=head3 Example 4: Building objects

This is the real, "scratch-my-itch" reason for this module: to be able to take
multi-level data generated by SQL, and build objects from
the returned data, in this example Moose objects.

The hypothetical situation being modelled in the database 
is that patients make multiple
visits to a doctor on several occasions and on each visit receive a diagnosis
of their condition.

So object I<Visit> has three attributes, the date the visit took place, the
name of the doctor, and the diagnosis. Object I<Patient> has a first and last
name and a list of Visits. To keep it simple, all scalar attributes are
strings. We assume all patients have unique (First, Last) name pairs.

  package Visit;
  use Moose;
  has  date      => (is => 'ro', isa => 'Str');
  has  doctor    => (is => 'ro', isa => 'Str');
  has  diagnosis => (is => 'ro', isa => 'Str');

  package Patient;
  use Moose;
  has last      => (is => 'ro', isa => 'Str'); 
  has first     => (is => 'ro', isa => 'Str'); 
  has Visits    => (is => 'ro', isa => 'ArrayRef[Visit]');

  no Moose;

  use DBI;

  ...

  my @result;     # this will contain a list of Patient objects

  my $sql = q{
    SELECT
       P.Last, P.First
      ,V.Date, V.Doctor, V.Diagnosis
    FROM
      Patient P
      ,Visit  V
    WHERE
      V.Patient_key = P.Patient_key   -- join clause
      ...
    ORDER BY
       P.Last, P.First
  };

  my $dbh = DBI->connect(...);

  my $data = $dbh->selectall_arrayref($sql);

  # rows of @$data contain: Last, First, Date, Doctor, Diagnosis
  #           at positions: [0]   [1]    [2]   [3]     [4]

  my $iter = igroup_by(
                data    => $data,
                compare => \&str_row_equal,
                args    => [ 0, 1 ],
                      );

  while (my $subset = $iter->()) {

    my @visits = map { Visit->new(
                        date        => $_[2],
                        doctor      => $_[3],
                        diagnosis   => $_[4],
                                 )
                     } @$subset;

    push @result, Patient->new(
                        last  => $subset->[0]->[0],
                        first => $subset->[0]->[1],
                        Visit => \@visits,
                              );
  }
  
See C<t/6.t> for code.

=head1 DIAGNOSTICS

Most error diagnostics are generated by the C<Params::Validate> module
which C<igroup_by()> uses for argument validation.

The C<data =E<gt> ...> and C<compare =E<gt> ...> parameters are mandatory. 



( run in 0.526 second using v1.01-cache-2.11-cpan-39bf76dae61 )