Why not adopt me?
NAME
Tie::RangeHash - Allows hashes to associate values with a range of keys
REQUIREMENTS
Algorithm::SkipList is required. Otherwise it uses standard modules.
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'
;
Custom comparison routines to support alternate datatypes can be implemented by specifying a new node type for Algorithm::SkipList.
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. - add
-
Adds a new key/value pair to the object.
$obj
->add(
$key
,
$value
);
$key
may be a string value in the form oflow,high
(for example, "Samantha,Selma"). - fetch
-
$value
=
$obj
->fetch(
$key
);
Returns the value associated with
$key
. ($key
may be in the form oflow,high
or any key betweenlow
andhigh
.)If they key range overlaps multiple keys, it will return a fatal error. In such cases, use "fetch_overlap".
- fetch_overlap
-
@values
=
$obj
->fetch_overlap(
"$low,$high"
);
Retrieves multiple values associated with a range of keys between
$low
and$high
. Capable of fetching values from overlapping keys.See "KNOWN ISSUES" for more information about overlapping keys.
- fetch_key
-
$real_key
=
$obj
->fetch_key(
$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 c<true> if
$key
has been defined (even if the value isundef
). ($key
is in the same form as is used by the "fetch" method.) - clear
-
$obj
->clear();
Deletes all keys and values defined in the object.
- 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 thefetch
method.) If$key
is not the exactlow,high
range, a warning will be emitted. - first_key
-
$key
=
$obj
->first_key();
Returns the first.
- next_key
-
$key
=
$obj
->next_key(
$last_key
);
Returns the next key in the iteration.
Implementation Notes
Internally, the hash uses skip lists. Skip lists are an alternative to binary trees. For more information, see Algorithm::SkipList.
Future versions may be changed to use something else that is more efficient.
KNOWN ISSUES
The is a new version of the module and has behaves differently compared to older versions. This is due to using the Algorithm::SkipList module for maintaining the underlying data rather than re-implementing it. While this improves the maintainability with the code, it increases incompatability with previous versions.
Some of the changes include:
- Overlapping keys cause fatal errors instead of warnings
-
Because the key comparison is now performed in the skip list node, there is no obvious way for it to give a warning and return a meaningful result. So instead the code dies. If you code relies on the possibility of using overlapping keys, then it may be more appropriate to have it test the code:
eval
{
$hash
{
'111,999'
} =
$value
;
};
This error can also occur by merely testing a hash, so it is important to run some checks if you are testing hash ranges:
eval
{
if
(
$hash
{
'111,999'
} ==
$value
) { ... }
}
Another option is to use "fetch_overlap" instead.
- Keys can be redefined
-
Nodes can now be redefined. For example:
$hash
{
'1,3'
} =
$value
;
...
$hash
{
'1,3'
} =
$new_value
;
...
$hash
{
'2'
} =
$new_value
;
Note that a range is no longer required.
- Non-range keys can be added.
-
When inserting a key,
$hash{'x'}
will be treated like$hash{'x,x'}
. - Open-ended ranges are allowed.
-
Open ended ranges are now supported. So the following can be added:
$hash
{
',10'
} =
$upper_bound
;
$hash
{
'11,'
} =
$lower_bound
;
Note that once open-ended ranges are defined, they are permenently open-ended unless the final range is deleted. Thus,
$hash
{
'12,13'
}
refers to the key
"11,"
. - Array references can no longer be keys.
-
The following is not supported anymore:
$hash
{ \
@array
) =
$value
;
- warnings no longer registered.
-
Warning registration is no longer used. This may change in the future.
- Custom separators and comparisons are not supported.
-
Only commas can be used as separators.
To customize separators and comparisons, you will have to specify a custom
Algorithm::SkipList::Node
method.
See the Changes file for a more complete list of changes and incompatabilities.
If your code does not rely on these quirks, then you should be able to substitute with no problems.
SEE ALSO
A module with similar functionality for numerical values is Array::IntSpan.
Algorithm::SkipList for more information on skip lists.
AUTHOR
Robert Rothenberg <rrwo at cpan.org>
Acknowledgements
Charles Huff <charleshuff atdecisionresearch.com> for suggestions and bug reports.
Sam Tregar <sam at 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-2008 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.