Joseph Brenner
and 1 contributors

NAME

Data::Math - arithmetic operations on complex data structures

SYNOPSIS

   use Data::Math;
   my $db = Data::Math->new();

   # add values in two parallel structures
   my $data_sum = $dm->calc( '+', $data_structure_1, $data_structure_2 );


   # subtracting data structures
   %gross = ( de => 2345.37,
              es => 1238.99,
              us => 1.98,
             );
   %costs = ( de => 35.00,
              es => 259.11,
              us => 666.66,
             );
   my $net = $dm->calc( '-', \%gross, \%costs );

   #    $net:
   #         { 'de' => '2310.37',
   #           'es' => '979.88',
   #           'us' => '-664.68' };

DESCRIPTION

Data::Math is for doing arithmetic operations on roughly parallel data structures.

It's pretty clear what a line like this would be meant to do, though Perl does nothing useful with it:

   %net = %gross - %costs;

Instead, Data::Math's calc method can be used:

   my $net = $dm->calc( '-', \%gross, \%costs );

The code here is customizeable in many ways, but has defaults that should make it easy to use in simple cases. The arithmetic operator is applied to numbers, strings are just passed through if both sides are the same, or concatenated (with '|' separator) if they differ.

If there's a numeric field you don't want to do numeric operations on (e.g. 'tax_rate') you can define a pattern in the object's skip_key_patterns array to skip it.

METHODS

new

Creates a new Data::Math object.

Takes a hash as an argument (i.e. a list of key/value pairs), to provide named fields that become object attributes. These attributes are:

string_policy

If the values aren't numbers, instead of the numeric operation, they'll be handled according to the string_policy. The default is concat_if_differ. If there are two different strings, they will be joined together using the join_char (if not, the string is just passed through).

Other allowed settings for string_policy:

   "pick_one"   if there are two different values, use the first one.
   "pick_2nd"   if there are two different values, use the second.
join_char

Defaults to "|".

skip_key_patterns

Skip numeric operation on keys that match any of this list of patterns.

skip_policy

Default: "pick_one", meaning that when we skip applying the numeric operation, by default we'll just pass through the value unchanged, picking the first if they differ.

The set of allowed skip policies is a superset of the string_policies. In addition to a string_policy, there's also the 'remove_key' policy, which will remove the matching keys from the result set.

calc

Takes an arithmetic operator given as a quoted string as the first argument and applies it to the following references to data structures.

Allowed operators: '+', '-', '*', '/' and '%'

do_calc

do_calc does recursive descent of two roughly parallel perl structures, performing the indicated operation on each, storing the result in a newly created parallel structure (a reference passed in as the third argument).

Typically, the indicated operation is a simple numeric operator, defaulting to '+'. The operator may be supplied as the 'op' option:

    $self->do_calc( $structure1, $structure2, $result_structure, { op => '-' };
qualify_hash

Given two hash references, returns a joint list of keys, and two "qualified" versions of the hashes, where undef values are replaced with default values based on the type of what's in the parallel location in the other hash.

Example usage:

  my ($keys, $qh1, $qh2) = $self->qualify_hash( $ds1, $ds2 );
qualify_array

Given two array references, returns the maximum index limit and two "qualified" versions of the arrays, where undef values are replaced with default values based on the type of what's in the parallel location in the other hash.

Example usage:

   my ( $limit, $aref1, $aref2 ) = $self->qualify_array( $aref1, $aref2 );
numeric_handler

Perform the indicated numeric operation on the two arguments. The operation is passed in as an option named "op", included in the options hashref in the third position.

Example usage:

    my $result =
      $self->numeric_handler( $ds1, $ds2, { op => '-' } );
string_handler

Handle two string arguments, according to the "string_policy" defined for this object. The default string handling behavior is to pass through the existing string if there's just one available or if there are two, to concatenate them using the object's "join_char" (typically a '|').

Other allowed values of "string_policy" are:

   "pick_one"   if there are two different values, use the first one.
   "pick_2nd"   if there are two different values, use the second.

Example usage:

    my $result = $self->string_handler( $ds1, $ds2 );

    # override object level string_policy
    my $result = $self->string_handler( $ds1, $ds2, 'pick_one' );

TODO

  o  look into 'preserve_source' options and such to
     improve memory efficiency

  o  try an operator overload interface

  o  examine possibility of arbitrary user-defineable
     operations (pattern/action callbacks?)

AUTHOR

Joseph Brenner, <doom@kzsu.stanford.edu>

COPYRIGHT AND LICENSE

Copyright (C) 2016 by Joseph Brenner

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://dev.perl.org/licenses/ for more information.