NAME
Array::AsHash - Treat arrays as a hashes, even if you need references for keys.
VERSION
Version 0.32
SYNOPSIS
use Array::AsHash;
my $array = Array::AsHash->new({
array => \@array,
clone => 1, # optional
});
while (my ($key, $value) = $array->each) {
# sorted
...
}
my $value = $array->get($key);
$array->put($key, $value);
if ( $array->exists($key) ) {
...
}
$array->delete($key);
DESCRIPTION
Sometimes we have an array that we need to treat as a hash. We need the data ordered, but we don't use an ordered hash because it's already an array. Or it's just quick 'n easy to run over array elements two at a time. This module allows you to use the array as a hash but also mostly still use it as an array, too.
Because we directly use the reference you pass to the constructor, you may wish to copy your data if you do not want it altered (the data are not altered except through the publicly available methods of this class).
EXPORT
None.
CONSTRUCTOR
new
my $array = Array::AsHash->new;
# or
my $array = Array::AsHash->new( { array => \@array } );
Returns a new Array::AsHash
object. If an array is passed to new
, it must contain an even number of elements. This array will be treated as a set of key/value pairs:
my @array = qw/foo bar one 1/;
my $array = Array::AsHash->new({array => \@array});
print $array->get('foo'); # prints 'bar'
Note that the array is stored internally and changes to the Array::AsHash
object will change the array that was passed to the constructor as an argument. If you do not wish this behavior, clone the array beforehand or ask the constructor to clone it for you.
my $array = Array::AsHash->new(
{
array => \@array,
clone => 1,
}
);
Internally, we use the Clone module to clone the array. This will not always work if you are attempting to clone objects (inside-out objects are particularly difficult to clone). If you encounter this, you will need to clone the array yourself. Most of the time, however, it should work.
Of course, you can simply create an empty object and it will still work.
my $array = Array::AsHash->new;
$array->put('foo', 'bar');
You may also specify strict
mode in the constructor.
my @array = qw/foo bar one 1/;
my $array = Array::AsHash->new(
{
array => \@array,
strict => 1,
}
);
print $array->get('foo'); # prints 'bar'
print $array->get('oen'); # croaks
If you specify "strict" mode, the following methods will croak if they attempt to access a non-existent key:
get
put
get_pairs
delete
In strict mode, instead of put
, you will want to use the add
method to add new keys to the array.
HASH-LIKE METHODS
The following methods allow one to treat an Array::AsHash object more-or-less like a hash.
keys
my @keys = $array->keys;
Returns the "keys" of the array. Returns an array reference in scalar context.
values
my @values = $array->values;
Returns the "values" of the array. Returns an array reference in scalar context.
delete
my @values = $array->delete(@keys);
Deletes the given @keys
from the array. Returns the values of the deleted keys. In scalar context, returns an array reference of the keys.
As a "common-case" optimization, if only one key is requested for deletion, deletion in scalar context will result in the one value (if any) being returned instead of an array reference.
my $deleted = $array->delete($key); # returns the value for $key
my $deleted = $array->delete($key1, $key2); # returns an array reference
Non-existing keys will be silently ignored unless you are in "strict" mode in which case non-existent keys are fatal.
clear
$array->clear;
Clears all of the values from the array.
each
while ( my ($key, $value) = $array->each ) {
# iterate over array like a hash
}
Lazily returns keys and values, in order, until no more are left. Every time each() is called, will automatically increment to the next key value pair. If no more key/value pairs are left, will reset itself to the first key/value pair.
If called in scalar context, returns an Array::AsHash::Iterator which behaves the same way (except that the iterator will not return another iterator if called in scalar context).
my $each = $array->each;
while ( my ($key, $value) = $each->next ) {
# iterate over array like a hash
}
See the Array::AsHash::Iterator object for available methods.
As with a regular hash, if you do not iterate over all of the data, the internal pointer will be pointing at the next key/value pair to be returned. If you need to restart from the beginning, call the reset_each
method.
kv
while ( my ($key, $value) = $array->kv ) {
# iterate over array like a hash
}
kv
is a synonym for each
.
first
if ($array->first) { ... }
Returns true if we are iterating over the array with each()
and we are on the first iteration.
last
if ($array->last) { ... }
Returns true if we are iterating over the array with each()
and we are on the last iteration.
reset_each
$array->reset_each;
Resets the each
iterator to point to the beginning of the array.
exists
if ($array->exists($thing)) { ... }
Returns true if the given $thing
exists in the array as a key.
get
my $value = $array->get($key);
Returns the value associated with a given key, if any. If a single key is passed and the key does not exist, returns an empty list. This means that the following can work correctly:
if (my @value = $array->get('no_such_key')) { ... }
If passed more than one key, returns a list of values associated with those keys with undef
used for any key whose value does not exist. That means the following will probably not work as expected:
if (my @value = $array->get('no_such_key1', 'no_such_key2') { ... }
If using a strict hash, get
will croak if it encounters a non-existent key.
put
$array->put($key, $value);
Sets the value for a given $key
. If the key does not already exist, this pushes two elements onto the end of the array.
Also accepts an even-sized list of key/value pairs:
$array->put(@kv_pairs);
If using a strict hash, put
will croak if it encounters a non-existent key. You will have to use the add
method to add new keys.
add
$array->add($key, $value);
add
behaves exactly like put
except it can only be used for adding keys. Any attempt to add
an existing key will croak regardless of whether you are in strict mode or not.
get_pairs
my $array = Array::AsHash->new({array => [qw/foo bar one 1 two 2/]});
my @pairs = $array->get_pairs(qw/foo two/); # @pairs = (foo => 'bar', two => 2);
my $pairs = $array->get_pairs(qw/xxx two/); # $pairs = [ two => 2 ];
get_pairs
returns an even-size list of key/value pairs. It silently discards non-existent keys. In scalar context it returns an array reference.
This method is useful for reordering an array.
my $array = Array::AsHash->new({array => [qw/foo bar two 2 one 1/]});
my @pairs = $array->get_pairs(sort $array->keys);
my $sorted = Array::AsHash->new({array => \@pairs});
If using a strict hash, get_pairs
will croak if it encounters a non-existent key.
default
$array->default(@kv_pairs);
Given an even-sized list of key/value pairs, each key which does not already exist in the array will be set to the corresponding value. Keys which already exist will be silently ignored, even in strict mode.
rename
$array->rename($old_key, $new_key);
$array->rename(@list_of_old_and_new_keys);
Rename $old_key
to $new_key
. Will croak if $old_key
does not exist, $new_key
already exists or $new_key
is undefined.
Can take an even-sized list of old and new keys.
hcount
my $pair_count = $array->hcount;
Returns the number of key/value pairs in the array.
hindex
my $index = $array->hindex('foo');
Returns the hash index of a given key, if the keys exists. The hash index is the array index divided by 2. In other words, it's the index of the key/value pair.
ARRAY-LIKE METHODS
The following methods allow one to treat a Array::AsHash object more-or-less like an array.
shift
my ($key, $value) = $array->shift;
Removes the first key/value pair, if any, from the array and returns it. Returns an array reference in scalar context.
pop
my ($key, $value) = $array->pop;
Removes the last key/value pair, if any, from the array and returns it. Returns an array reference in scalar context.
unshift
$array->unshift(@kv_pairs);
Takes an even-sized list of key/value pairs and attempts to unshift them onto the front of the array. Will croak if any of the keys already exists.
push
$array->push(@kv_pairs);
Takes an even-sized list of key/value pairs and attempts to push them onto the end of the array. Will croak if any of the keys already exists.
insert_before
$array->insert_before($key, @kv_pairs);
Similar to splice(), this method takes a given $key
and attempts to insert an even-sized list of key/value pairs before the given key. Will croak if $key
does not exist or if @kv_pairs
is not an even-sized list.
$array->insert_before($key, this => 'that', one => 1);
insert_after
$array->insert_after($key, @kv_pairs);
This method takes a given $key
and attempts to insert an even-sized list of key/value pairs after the given key. Will croak if $key
does not exist or if @kv_pairs
is not an even-sized list.
$array->insert_after($key, this => 'that', one => 1);
key_at
my $key = $array->key_at($index);
my @keys = $array->key_at(@indices);
This method takes a given index and returns the key for that index. If passed a list of indices, returns all keys for those indices, just like an array slice. If passed a single value, always returns a scalar. Otherwise, returns an array ref in scalar context.
value_at
my $value = $array->value_at($index);
my @values = $array->value_at(@indices);
This method takes a given index and returns the value for that index. If passed a list of indices, returns all values for those indices, just like an array slice. If passed a single value, always returns a scalar. Otherwise, returns an array ref in scalar context.
acount
my $count = $array->acount;
Returns the number of elements in the array.
aindex
my $count = $array->aindex('foo');
Returns the array index of a given key, if the keys exists.
MISCELLANEOUS METHODS
strict
if ($array->strict) {
...
}
$array->strict(0); # turn off strict mode
Getter/setter for validating strict mode. If no arguments are passed, returns a boolean value indicating whether or not strict mode has been enabled for this array.
If an argument is passed, sets strict mode for the array to the boolean value of the argument.
get_array
my @array = $array->get_array;
Returns the array in the object. Returns an array reference in scalar context. Note that altering the returned array can affect the internal state of the Array::AsHash object and will probably break it. You should usually only get the underlying array as the last action before disposing of the object. Otherwise, attempt to clone the array with the clone
method and use that array.
my @array = $array->clone->get_array;
clone
my $array2 = $array->clone;
Attempts to clone (deep copy) and return a new object. This may fail if the array contains objects which Clone cannot handle.
OVERLOADING
The boolean value of the object has been overloaded. An empty array object will report false in boolean context:
my $array = Array::AsHash->new;
if ($array) {
# never gets here
}
The string value of the object has been overloaded to ease debugging. When printing the reference, the output will be in the following format:
key1
value1
key2
value2
key3
value3
This is a bit unusual but since this object is neither an array nor a hash, a somewhat unusual format has been chosen.
CAVEATS
Internally we keep the array an array. This does mean that things might get a bit slow if you have a large array, but it also means that you can use references (including objects) as "keys". For the general case of fetching and storing items you'll find the operations are O(1)
. Behaviors which can affect the entire array are often O(N)
.
We achieve O(1)
speed for most operations by internally keeping a hash of key indices. This means that for common use, it's pretty fast. If you're writing to the array a lot, it could be a bit slower for large arrays. You've been warned.
WHY NOT A TIED HASH?
You may very well find that a tied hash fits your purposes better and there's certainly nothing wrong with them. Personally, I do not use tied variables unless absolutely necessary because ties are frequently buggy, they tend to be slow and they take a perfectly ordinary variable and make it hard to maintain. Return a tied variable and some poor maintenance programmer is just going to see a hash and they'll get awfully confused when their code isn't doing quite what they expect.
Of course, this module provides a richer interface than a tied hash would, but that's just another benefit of using a proper class instead of a tie.
AUTHOR
Curtis "Ovid" Poe, <ovid@cpan.org>
BUGS
Please report any bugs or feature requests to bug-array-ashash@rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Array-AsHash. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SEE ALSO
COPYRIGHT & LICENSE
Copyright 2005 Curtis "Ovid" Poe, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.