Tie::RangeHash - Allows hashes to associate values with a range of keys


NAME

Tie::RangeHash - Allows hashes to associate values with a range of keys


REQUIREMENTS

Tie::RangeHash is written for and tested on Perl 5.6.0.

It uses only standard modules.

Installation

Installation is pretty standard:

  perl Makefile.PL
  make
  make test
  make install

Note that when you run the tests, you will see warnings. That is intentional.


SYNOPSIS

  use Tie::RangeHash;
  tie %hash, 'Tie::RangeHash';
  $hash{'A,C'} = 1;
  $hash{'D,F'} = 2;
  $hash{'G,K'} = 3;
  $hash{'E'};           # returns '2'
  $hash{'BB'};          # returns '1'
  $hash{'KL'};          # returns nothing ('undef')

There is also an object-oriented interface:

  $hash = new Tie::RangeHash;
  $hash->add('A,C', 1);
  $hash->add('G,I', 2);
  $hash->fetch('H');    # returns '2'


DESCRIPTION

This module allows hashes to associate a value with a range of keys rather than a single key.

For example, you could pass date ranges to the hash and then query it with a specific date, like so:

  $cost{'1999-12-15,2000-01-14'} = 150;
  $cost{'2000-01-15,2000-02-14'} = 103;
  $cost{'2000-02-15,2000-03-14'} =  97;

and then query the cost on a specific date:

  $this_cost = $cost{'2000-02-08'};

Numeric key ranges can also be used:

  tie %hash, 'Tie::RangeHash', {
    Type => Tie::RangeHash::TYPE_NUMBER
  };
  $hash{'1.4,1.8'}      = 'Jim';
  $hash{'1.0,1.399999'} = 'Ned';
  $hash{'1.800001,2.0'} = 'Boo';

If string or numeric comparisons are not appropriate for the keys you need, a custom comparison routine can be specified:

  sub reverse_compare {
    my ($A, $B) = @_;
    return ($B cmp $A);
  }
  tie %hash, 'Tie::RangeHash', {
    Comparison => \&reverse_compare
  };

The comparison routine should work the same as custom sort subroutines do (A < B returns -1, A=B returns 0, A > B returns 1). Your keys must also be representable as a string (a future version of this module may add filters to overcome that limitation).

If you need to define your own separator, you can do so:

  tie %hash, 'Tie::RangeHash', {
    Separator => '..'
   };

or

  tie %hash, 'Tie::RangeHash', {
    Separator => qr/\s/
   };

Note that if you define it as a regular expression, warnings and errors will use the default comma ',' separator (since there is no way to ``reverse'' a regular expression).

You can also specify array references for keys and do away with separators:

  $hash{ [ qw( A C ) ] } = 1;

Object-Oriented Interface

Tie::RangeHash has an object-oriented interface as an alternative to using a tied hash.

new
Creates a new object.
  $OBJ = Tie::RangeHash->new( \%ATTR );

%ATTR is a hash containing the attributes described above. This is the same as the TIEHASH method used for tied hashes.

add
Adds a new key/value pair to the object.
  $OBJ->add( $KEY, $VALUE );

$KEY may be a string value in the form of low,high or an array reference in the form of [ low, high ]. This is the same as the STORE method used for tied hashes.

fetch
  $VALUE = $OBJ->fetch( $KEY );

Returns the value associated with $KEY. ($KEY may be in the form of low,high or a key between low and high.) This is the same as the FETCH method used for tied hashes.

fetch_key
  $REAL_KEY = $OBJ->fetch( $KEY );
  ($REAL_KEY, $VALUE) = $OBJ->fetch( $KEY );

Like fetch, but it returns the key range that was matched rather than the value. If it is called in an array context, it will return the key and value.

key_exists
  if ($OBJ->key_exists( $KEY )) { .. }

Returns true if $KEY has been defined (even if the value is undef). ($KEY is in the same form as is used by the fetch method.) This is the same as the EXISTS method used for tied hashes.

It is called key_exists so as not to be confused with the exists keyword in Perl.

clear
  $OBJ->clear();

Deletes all keys and values defined in the object. This is the same as the CLEAR method used for tied hashes.

remove
  $VALUE = $OBJ->remove( $KEY );

Deletes the $KEY from the object and returnes the associated value. ($KEY is in the same form as is used by the fetch method.) If $KEY is not the exact low,high range, a warning will be emitted. This is the same as the DELETE method used for tied hashes.

It is called remove so as not to be confused with the delete keyword in Perl.

Implementation Notes

Internally, the hash is actually a binary tree. Values are retrieved by searching the tree for nodes that where the key is within range. This module has nothing to do with ``range trees''.

The binary-tree code is spontaneously written and has a very simple tree-banacing scheme. It appears to work, but has not been fully tested.

A future version of this module may use an improved binary-tree algorithm. Or it may use something else.


KNOWN ISSUES

Duplicate and overlapping ranges are not supported. Once a range is defined, it exists until you delete it or clear the hash.

Warnings are now disabled by default unless you run Perl with the -W flag. In theory, you should also be able to say

  use warnings 'Tie::RangeHash';

but this does not always seem to work. (Apparently something is broken with warnings in Perl 5.6.0.)

This module is incomplete for a tied hash: it has no FIRSTKEY or NEXTKEY methods (pending my figuring out a good way to implement them).


SEE ALSO

A module with similar functionality for numerical values is Array::IntSpan.


AUTHOR

Robert Rothenberg <rrwo@cpan.org>

Acknowledgements

Charles Huff <charleshuff@decisionresearch.com> for suggestions and bug reports.

Sam Tregar <sam@tregar.com> for optimization suggestions.

Various Perl Monks <http://www.perlmonks.org> for advice and code snippets.

Suggestions and Bug Reporting

Feedback is always welcome. Please use the CPAN Request Tracker at http://rt.cpan.org to submit bug reports.


LICENSE

Copyright (c) 2000-2002 Robert Rothenberg. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

 Tie::RangeHash - Allows hashes to associate values with a range of keys