multikey(3)

NAME

Hash::MultiKey - hashes whose keys can be multiple

SYNOPSIS

use Hash::MultiKey;
# tie first
tie %hmk, 'Hash::MultiKey';
# store
$hmk{['foo', 'bar', 'baz']} = 1;
# fetch
$v = $hmk{['foo', 'bar', 'baz']};
# exists
exists $hmk{['foo', 'bar', 'baz']}; # true
# each
while (($mk, $v) = each %hmk) {
    @keys = @$mk;
    # ...
}
# keys
foreach $mk (keys %hmk) {
    @keys = @$mk;
    # ...
}
# values
foreach $v (values %hmk) {
    $v =~ s/foo/bar/g; # alias, modifies value in %hmk
    # ...
}
# delete
$rmed_value = delete $hmk{['foo', 'bar', 'baz']};
# clear
%hmk = ();
# syntactic sugar, but see risks below
$hmk{'foo', 'bar', 'baz', 'zoo'} = 2;
# finally, untie
untie %hmk;

DESCRIPTION

Hash::MultiKey provides hashes that accept arrayrefs of
strings as keys.

Two multi-keys are regarded as being equal if their con_
tents are equal, there is no need to use the same refer
ence to refer to the same hash entry:
$hmk{['foo', 'bar', 'baz']} = 1;
exists $hmk{['foo', 'bar', 'baz']}; # different ar
rayref, but true
A given hash can have multi-keys of different lengths:

$hmk{['foo']} = 1; # length 1
$hmk{['foo', 'bar', 'baz']} = 3; # length 3, no prob
lem
In addition, multi-keys cannot be empty:

$hmk{[]} = 1; # ERROR
The next sections document how hash-related operations
work in a multi-key hash. Some parts have been copied from
standard documentation, since everything has standard
semantics.
tie
Once you have tied a hash variable to Hash::MultiKey as in

tie my (%hmk), 'Hash::MultiKey';
you've got a hash whose keys are arrayrefs of strings.
Having that in mind everything works as expected.
store
Assignment is this easy:

$hmk{['foo', 'bar', 'baz']} = 1;
fetch
So is fetching:

$v = $hmk{['foo', 'bar', 'baz']};
exists
Testing for existence works as usual:

exists $hmk{['foo', 'bar', 'baz']}; # true
Only whole multi-keys as they were used in assigments have
entries. Sub-chains do not exist unless they were
assigned some value.
For instance, "['foo']" is a sub-chain of "['foo', 'bar',
'baz']", but if it has no entry in %hmk so far

exists $hmk{['foo']}; # false
each
As with everyday "each()", when called in list context
returns a 2-element list consisting of the key and value
for the next element of the hash, so that you can iterate
over it. When called in scalar context, returns only the
key for the next element in the hash.
Remember keys are arrayrefs of strings here:

while (($mk, $v) = each %hmk) {
@keys = @$mk;
# ...
}
The order in which entries are returned is guaranteed to
be the same one as either the "keys()" or "values()" func
tion would produce on the same (unmodified) hash.
When the hash is entirely read, a null array is returned
in list context (which when assigned produces a false (0)
value), and "undef" in scalar context. The next call to
"each()" after that will start iterating again.
There is a single iterator for each hash, shared by all
"each()", "keys()", and "values()" function calls in the
program.
Adding or deleting entries while we're iterating over the
hash results in undefined behaviour. Nevertheless, it is
always safe to delete the item most recently returned by
"each()", which means that the following code will work:

while (($mk, $v) = each %hmk) {
print "@$mk0;
delete $hmk{$mk}; # this is safe
}
keys
Returns a list consisting of all the keys of the named
hash. (In scalar context, returns the number of keys.) The
keys are returned in an apparently random order. The
actual random order is subject to change in future ver
sions of perl, but it is guaranteed to be the same order
as either the "values()" or "each()" function produces
(given that the hash has not been modified). As a side
effect, it resets hash's iterator.
Remember keys are arrayrefs of strings here:

foreach $mk (keys %hmk) {
@keys = @$mk;
# ...
}
There is a single iterator for each hash, shared by all
"each()", "keys()", and "values()" function calls in the
program.
The returned values are copies of the original keys in the
hash, so modifying them will not affect the original hash.
Compare "values()".
values
Returns a list consisting of all the values of the named
hash. (In a scalar context, returns the number of values.)
The values are returned in an apparently random order. The
actual random order is subject to change in future ver
sions of perl, but it is guaranteed to be the same order
as either the "keys()" or "each()" function would produce
on the same (unmodified) hash.
Note that the values are not copied, which means modifying
them will modify the contents of the hash:

s/foo/bar/g foreach values %hmk; # modifies
%hmk's values
s/foo/bar/g foreach @hash{keys %hash}; # same
As a side effect, calling "values()" resets hash's inter
nal iterator.
There is a single iterator for each hash, shared by all
"each()", "keys()", and "values()" function calls in the
program.
delete
Deletes the specified element(s) from the hash. Returns
each element so deleted or the undefined value if there
was no such element.
The following (inefficiently) deletes all the values of
%hmk:

foreach $mk (keys %hmk) {
delete $hmk{$mk};
}
And so do this:

delete @hmk{keys %hmk};
But both methods are slower than just assigning the empty
list to %hmk:

%hmk = (); # clear %hmk, the efficient way
untie
Untie the variable when you're done:

untie %hmk;

SYNTACTIC SUGAR

Hash::MultiKey supports also this syntax:
$hash{'see', '$;', 'in', 'perldoc', 'perlvar'} = 1;
If the key is a string instead of an arrayref the underly
ing code splits it using $; (see why in MOTIVATION) and
from then on the key is an arrayref as any true multi-key.
Thus, the assigment above is equivalent to

$hash{['see', '$;', 'in', 'perldoc', 'perlvar']} = 1;
once it has been processed.
You don't need to split the string back while iterating
with "each()" or "keys()", it already comes as an arrayref
of strings.
Nevertheless take into account that this is slower, and
broken if any of the components contains $;. It is sup
ported just for consistency's sake.

MOTIVATION

Perl comes already with some support for hashes with
multi-keys. As you surely know, if perl sees
$hash{'foo', 'bar', 'baz'} = 1;
it joins "('foo', 'bar', 'baz')" with $; to obtain the
actual key, thus resulting in a string. Then you retrieve
the components of the multi-key like this:

while (($k, $v) = each %hash) {
@keys = $k eq '' ? ('') : split /$;/, $k, -1;
# ...
}
Since $; is " 34" by default, a non-printable character,
this is often enough.
Sometimes, however, that's not the most convenient way to
work with multi-keys. For instance, that magic join
doesn't work with arrays:

@array = ('foo', 'bar', 'baz');
$hash{@array} = 1; # WARNING, @array evaluated in
scalar context!
You could be dealing with binary data. Or you could be
writing a public module that uses user input in such a
hash and don't want to rely on input not coming with $;,
or don't want to document such an obscure, gratuitous, and
implementation dependent constraint.
In such cases, Hash::MultiKey can help.

AUTHORS

Xavier Noria (FXN), Benjamin Goldberg (GOLDBB).

THANKS

Iain Truskett (SPOON) kindly checked whether this module
works in perl 5.005 and found out the use of "/" in
"pack()", introduced in perl 5.006, prevents that.

Philip Monsen reported some tests of Hash::MultiKey 0.05
failed with perl 5.8.4.

COPYRIGHT and LICENSE

Copyright (C) 2003, Xavier Noria <fxn@cpan.org>. All
rights reserved. This module is free software; you can
redistribute it and/or modify it under the same terms as
Perl itself.

SEE ALSO

perlvar, perltie
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout