NAME

Data::Range::Compare::Stream - Compute intersections of Ranges with Iterators

SYNOPSIS

 use Data::Range::Compare::Stream;
 use Data::Range::Compare::Stream::Iterator::Array;
 use Data::Range::Compare::Stream::Iterator::Consolidate;
 use Data::Range::Compare::Stream::Iterator::Compare::Asc;

 # create the iterator for column_a's Consolidation iterator
 my $column_a=Data::Range::Compare::Stream::Iterator::Array->new();
 $column_a->create_range(3,11);
 $column_a->create_range(17,19);

 # create the iterator for column_b's Consolidation iterator
 my $column_b=Data::Range::Compare::Stream::Iterator::Array->new();
 $column_b->create_range(0,0);
 $column_b->create_range(1,3);
 $column_b->create_range(5,7);
 $column_b->create_range(6,9);
 $column_b->create_range(11,15);
 $column_b->create_range(17,33);

 # sort columns a and be in consolidate order
 $column_a->prepare_for_consolidate_asc;
 $column_b->prepare_for_consolidate_asc;

 # create the consolidator object for column_a our iterator to it
 my $column_a_consolidator=Data::Range::Compare::Stream::Iterator::Consolidate->new($column_a);

 # create the consolidator object for column_b our iterator to it
 my $column_b_consolidator=Data::Range::Compare::Stream::Iterator::Consolidate->new($column_b);

 # create the object that will compare columns a and b
 my $compare=new Data::Range::Compare::Stream::Iterator::Compare::Asc;

 # add column a for processing
 $compare->add_consolidator($column_a_consolidator);

 # add column b for processing
 $compare->add_consolidator($column_b_consolidator);


 # now we can compute the intersections of our objects

 while($compare->has_next) {
    # fetch our current result object
   my $row=$compare->get_next;
 
   # if no ranges overlap with this row move on
   next if $row->is_empty;
 
   # now we can output the current range
   my $common_range=$row->get_common;
   my $overlap_count=$row->get_overlap_count;
 
   print "A total of: [$overlap_count] Ranges intersected with Common range: $common_range\n";
 
   my $overlap_ids=$row->get_overlap_ids;
   for each my $consolidator_id (@{$overlap_ids}) {
 
     if($consolidator_id==0) {
 
       my $result=$row->get_consolidator_result_by_id($consolidator_id);
       print "  Column a contained the following overlaps $result\n";
 
     } elsif($consolidator_id==1) {
 
       my $result=$row->get_consolidator_result_by_id$consolidator_id);
       print "  Column b contained the following overlaps $result\n";
 
     }
 
   }
 
   print "\n";

 }

DESCRIPTION

The collection of modules to quickly compute intersections of 2 dimensional ranges with iterators.

Getting Started

The internals of Data::Range::Compare::Stream only support dealing with integers by default: This section covers how to Extend Data::Range::Compare::Stream to support your data types.

  • Creating a Package that supports comparing your Data Types

    If you are comparing anything other than integers then you will need to subclass Data::Range::Compare::Stream.

    Example Package that compares DateTime ranges
    
      package MyDateTypeRangeCompare;
      
      use strict;
      use warnings;
      use DateTime;
      use base qw(Data::Range::Compare::Stream);
      
      #
      # Define the class internals will use when creating a new object instance(s)
      use constant NEW_FROM_CLASS=>'MyDateTypeRangeCompare';
      
      sub cmp_values ($$) {
        my ($self,$value_a,$value_b)=@_;
        return DateTime->compare($value_a,$value_b);
      }
      
      sub add_one ($) {
        my ($self,$value)=@_;
        return $value->clone->add(seconds=>1);
      }
      
      sub sub_one ($) {
        my ($self,$value)=@_;
        return $value->clone->subtract(seconds=>1);
      }
      
      sub range_start_to_string {
        my ($self)=@_;
        return $self->range_start->strftime('%F %T');
      }
      
      sub range_end_to_string {
        my ($self)=@_;
        return $self->range_end->strftime('%F %T');
      }
    
      1;
  • Making use of your new package

    Once you have created a new package to compare your ranges with, you can start processing your data.

    Example how how to use the new module
    
      # load the package used to compare our ranges
      use MyDateTypeRangeCompare;
      
      # load our stream compare packages
      use Data::Range::Compare::Stream::Iterator::Array;
      use Data::Range::Compare::Stream::Iterator::Consolidate;
      use Data::Range::Compare::Stream::Iterator::Compare::Asc;
      
      # create the containers that we will use to sort our data
      #
      # Note: we are passing the name of our new class to the object constructors!
      my $vpn_a=new Data::Range::Compare::Stream::Iterator::Array(new_from=>'MyDateTypeRangeCompare');
      my $vpn_b=new Data::Range::Compare::Stream::Iterator::Array(new_from=>'MyDateTypeRangeCompare');;
      my $vpn_c=new Data::Range::Compare::Stream::Iterator::Array(new_from=>'MyDateTypeRangeCompare');;
      
      #
      # Outage block for vpn_a
      $vpn_a->create_range(
         DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute 01 second 59)),
         DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute 05 second 47))
      );
      
      $vpn_a->create_range(
         DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 41 second 32)),
         DateTime->new(qw(year 2010 month 05 day 02 hour 08 minute 00 second 16))
      );
      
      
      #
      # Outage block for vpn_b
      $vpn_b->create_range(
         DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 41 second 32)),
         DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 58 second 13))
      );
      
      $vpn_b->create_range(
         DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute 03 second 59)),
         DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute 04 second 37))
      );
      
      #
      # Outage block for vpn_c
      $vpn_c->create_range(
          DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute 03 second 59)),
          DateTime->new(qw(year 2010 month 01 day 02 hour 10 minute  04 second 37))
      );
      
      $vpn_c->create_range(
          DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 41 second 32)),
          DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 58 second 13))
      );
      
      $vpn_c->create_range(
          DateTime->new(qw(year 2010 month 05 day 02 hour 07 minute 59 second 07)),
          DateTime->new(qw(year 2010 month 05 day 02 hour 08 minute 00 second 16))
      );
      
      $vpn_c->create_range(
          DateTime->new(qw(year 2010 month 06 day 18 hour 10 minute 58 second 21)),
          DateTime->new(qw(year 2010 month 06 day 18 hour 22 minute 06 second 55))
        );
      
      # Make sure our list of vpns are sorted
      $vpn_a->prepare_for_consolidate_asc;
      $vpn_b->prepare_for_consolidate_asc;
      $vpn_c->prepare_for_consolidate_asc;
      
      # Create our compare object
      my $compare=Data::Range::Compare::Stream::Iterator::Compare::Asc->new;
      
      $compare->add_consolidator($column_a);
      $compare->add_consolidator($column_b);
      $compare->add_consolidator($column_c);
      
      my @column_names=(qw(vpn_a vpn_b vpn_c));
      
      while($compare->has_next) {
        my $row=$compare->get_next;
      
        # skip all rows that don't completely overlap
        next unless $row->all_overlap;
      
        my $common=$row->get_common;
      
        my $outage=$common->range_end->subtract_datetime($common->range_start);
        print "Common outage range: $common\n";
        print "Total Downtime: Months: $outage->{months} Days: $outage->{days} Minutes: $outage->{minutes} Seconds: $outage->{seconds}\n";
      
        for(my $id=0;$id<=$#column_names;++$id) {
          print $column_names[$id],' ',$row->get_consolidator_result_by_id($id)->get_common,"\n";
        }
        print "\n";
      }

OO Methods

This section covers the OO Methods in the package.

  • my $range=new Data::Range::Compare::Stream($range_start,$range_end);

  • my $range=new Data::Range::Compare::Stream($range_start,$range_end,$data);

    Object constructor:

    Creates a new instance of Data::Range::Compare::Stream
    
     Arguments an their meanings:
    
       $range_start -- Required
         Represents the start of this given range
    
       $range_end -- Required
         Represents the end of this range.
    
       $data -- Optional
         Used to tag this range with your data
  • my $value=$range->range_start

    Returns the object that represents the start of this range.
  • my $string=$range->range_start_to_string

    Returns a string that represents the start of the range.
  • my $value=$range->range_end

    Returns the object that represents the end of the rage.
  • my $string=$range->range_end_to_string;

    Returns a string that represents the end of the range.
  • my $new_value=$range->sub_one($value);

    Computes and returns the object that came before this $value
  • my $new_value=$range->add_one($value)

    Computes and returns the object that comes after this $value
  • my $cmp=$range->cmp_values($value_a,$value_b)

    Returns -1,0,1 similar to <=> or cmp.
  • my $next_range_start_value=$range->next_range_start

    Returns the starting value of the range that will come after this range.
  • my $previous_range_end_value=$range->previous_range_end

    Returns a value that represents the end of the range that precedes this one.
  • my $data=$range->data($optional_value);

      Used to get and set the data value for this range.
    
        Sets when called with an argument
    
          Example:
            
    	$range->data('some value');
    
        Gets the current data value when called without any arguments
        
          Example:
    
            my $value=$range->data;
  • my $class=$range->NEW_FROM_CLASS;

    Returns the name of the class new objects will be constructed from.
  • my $new_range=$get_common_range([$range_a,$range_b,$range_c]);

    Given an array reference of ranges that overlap $new_range will be the smallest intersecting range;
  • my $new_range=$range->get_overlapping_range([$range_a,$range_b,$range_c]);

    Given an array reference of ranges: $new_range will contain all of the ranges listed in the array reference
  • my $cmp=$range_a->cmp_range_start($range_b);

    Compares the starting values of $range_a and $range_b
    
      Returns: -1 0 1,see perlop: <=> or cmp
  • my $cmp=$range_a->cmp_range_end($range_b);

    Compares the ending values of $range_a and $range_b
    
      Returns: -1 0 1, see perlop: <=> or cmp
  • my $cmp=$range_a->cmp_range_start_to_range_end($range_b);

    Compares the start of $range_a to the end of $range_b
    
      Returns: -1 0 1, see perlop: <=> or cmp
  • if($range->contains_value($value)) { do something }

    Returns true if $range contains $value
  • if($range_a->contiguous_check($range_b)) { do something }

    Returns true if $range_a is immediately followed by $range_b.
  • my $cmp=$range_a->cmp_ranges($range_b);

    Compares $range_a to $range_b in Ascending order.
      
      Returns: -1 0 1, see perlop: <=> or cmp
  • if($range_a->overlap($range_b) { do something }

    Returns true if $range_a overlaps with $range_b

SEE ALSO

Data::Range::Compare::Stream::Cookbook

AUTHOR

Michael Shipper

Source-Forge Project

As of version 0.001 the Project has been moved to Source-Forge.net

Data Range Compare https://sourceforge.net/projects/data-range-comp/

COPYRIGHT

Copyright 2011 Michael Shipper. All rights reserved.

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