Re: Default Hash Key
by ikegami (Patriarch) on May 02, 2008 at 01:05 UTC
|
It can also be done using a tied hash (with a speed penalty). I don't see an existing module on CPAN after a quick look, but it's it's easy to write your own.
{
package Hash::WithDefault;
use Tie::Hash qw( );
BEGIN { our @ISA = 'Tie::ExtraHash'; }
use constant IDX_HASH => 0;
use constant IDX_DEFAULT => 1;
use constant NEXT_IDX => 2;
sub FETCH {
my ($self, $key) = @_;
return ( exists( $self->[IDX_HASH]{$key} )
? $self->[IDX_HASH]{$key}
: $self->[IDX_DEFAULT]
);
}
}
{
tie my %hash, 'Hash::WithDefault', 'not in the alphabet';
%hash = (
a => 'a vowel',
b => 'a consonant',
);
print("$_: $hash{$_}\n") for qw( a b ~ );
}
Output:
a: a vowel
b: a consonant
~: not in the alphabet
| [reply] [d/l] [select] |
|
| [reply] |
|
Thanks for looking, but that module doesn't do what the OP wants as far as I can tell.
| [reply] |
|
|
|
|
|
|
If I read the doc of Tie::Hash correctly, you should have used
use Tie::StdHash qw( );
Tie::Hash only provides a subset of the necessary hash methods
| [reply] [d/l] |
|
>perl -e"use Tie::StdHash qw( );"
Can't locate Tie/StdHash.pm in @INC (@INC contains: c:/Progs/perl588/l
+ib c:/Progs/perl588/site/lib .) at -e line 1.
BEGIN failed--compilation aborted at -e line 1.
Notice that I didn't actually inherit from Tie::Hash. I didn't inherit from Tie::StdHash either because it doesn't provide any means to store object attributes such as the default value. Tie::ExtraHash does.
| [reply] [d/l] [select] |
Re: Default Hash Key
by oko1 (Deacon) on May 02, 2008 at 02:28 UTC
|
Just in case you have an 'XY' problem in your question, here's a common solution for this class of thing:
my %description = (
a => 'a vowel',
b => 'a consonant'
);
for my $choice (qw/a b c/){
print "$choice is ", $description{$choice} || "not in the alphabet.
+", "\n";
}
Output:
a is a vowel
b is a consonant
c is not in the alphabet.
--
Human history becomes more and more a race between education and catastrophe. -- HG Wells
| [reply] [d/l] [select] |
|
Wow thanks for the reply okol (and for the benefit of the doubt!) I really learned a lot from all the replies, but yours is nice and simple and probably about as fast as possible.
I tried just a slight variation and I think it's going to work nicely.
use strict;
use warnings;
my %description = ( a => 'a vowel',
b => 'a consonant',
default => 'not in the alphabet' );
for my $char (qw/a b c/) {
my $d = $description{$char} || $description{default};
print("$char is $d\n");
}
I still can't quite get my head around the way that the logical or works. I would think that it would only return 1 or 0, but evidently here it's returning the whole string back again.
Anyway, thanks for all the help everybody. I did kinda post problem Y without getting into the specifics of problem X, but that was only because I thought X would bore everybody to tears! | [reply] [d/l] |
|
Just be careful about $description{foo} that evaluate to false:
use strict;
use warnings;
my %description = ( a => 'a vowel',
b => 'a consonant',
0 => '0',
default => 'not in the alphabet' );
for my $char (qw/a b c 0/) {
my $d = $description{$char} || $description{default};
print("$char is $d\n");
}
| [reply] [d/l] |
|
|
|
|
tford:
perldoc perlop yields:
C-style Logical Or
Binary "||" performs a short-circuit logical OR operation. That is, if
the left operand is true, the right operand is not even evaluated.
Scalar or list context propagates down to the right operand if it is
evaluated.
The "||" and "&&" operators return the last value evaluated (unlike C's
"||" and "&&", which return 0 or 1). Thus, a reasonably portable way to
find out the home directory might be:
$home = $ENV{'HOME'} || $ENV{'LOGDIR'} ||
(getpwuid($<))[7] || die "You're homeless!\n";
...roboticus
| [reply] [d/l] [select] |
Re: Default Hash Key
by TGI (Parson) on May 02, 2008 at 00:57 UTC
|
package DefaultHash;
sub TIEHASH {
my $class = shift;
my $default = shift;
my $self;
$self->{_DEFAULT} = $default;
$self->{_HASH} = {};
return bless $self, $class;
}
sub FETCH {
my $self = shift;
my $key = shift;
return
exists $self->{_HASH}{$key}
? $self->{_HASH}{$key}
: $self->{_DEFAULT}
}
sub EXISTS {
my $self = shift;
my $key = shift;
return exists $self->{_HASH}{$key};
}
sub FIRSTKEY {
my $self = shift;
my $foo = keys %{$self->{_HASH}}; # Reset each
return each %{$self->{_HASH}};
}
sub NEXTKEY {
my $self = shift;
return each %{$self->{_HASH}};
}
sub CLEAR {
my $self = shift;
$self->{_HASH} = {};
}
sub DELETE {
my $self = shift;
my $key = shift;
return delete $self->{_HASH}{$key};
}
sub STORE {
my $self = shift;
my $key = shift;
my $value = shift;
$self->{_HASH}{$key} = $value;
}
package main;
tie( my %hash, 'DefaultHash', 'a default value' );
%hash = ( a => 1, b => 2, c => 3 );
print "$_ => $hash{$_}\n" for qw(a b c d);
| [reply] [d/l] |
|
That's way way longer than it needs to be (and thus more error-prone and harder to maintain).
| [reply] |
|
| [reply] |
Re: Default Hash Key
by wade (Pilgrim) on May 02, 2008 at 00:32 UTC
|
You could always do something like:
my $foo = exists($description{$input})
? $description{$input}
: "default value";
Or the two-step approach:
my $foo = $description{$input};
$foo = "default value" if (!defined($foo));
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
Re: Default Hash Key
by toolic (Bishop) on May 02, 2008 at 00:52 UTC
|
Is there a way to define a default value for a hash?
I do not know. But, you could create a function to see if a key exists:
use warnings;
use strict;
my %description = (
a => 'a vowel',
b => 'a consonant'
);
print 'a is ', check(\%description, 'a'), "\n";
print 'b is ', check(\%description, 'b'), "\n";
print '~ is ', check(\%description, '~'), "\n";
sub check {
my ($href, $key) = @_;
return (exists $href->{$key}) ? $href->{$key} : 'not in the alphab
+et';
}
prints:
a is a vowel
b is a consonant
~ is not in the alphabet
| [reply] [d/l] [select] |
Re: Default Hash Key
by Anonymous Monk on May 07, 2008 at 02:09 UTC
|
In this case I would simply opt for “keep it simple.” Write a nice short sub that produces the effect that you want ... and move along.
There is no problem with doing an “if exists” test for a particular value followed by an apparent-lookup of that same value, because you can be quite sure that on that “second lookup” that value will be found most-immediately.
So, just go for an implementation that is reasonably clear, and trust the Gods of Perl to have done the rest on your behalf. (They're quite good at that sort of thing...)
| [reply] |