RE: Case insensitivity in a hash... Futile effort?
by vroom (His Eminence) on Apr 18, 2000 at 23:20 UTC
|
If you've got the Perl Cookbook look at Recipe 13.15. They show a lot of cool ways to use tie including the case insensitive hash, and an appending hash.
vroom | Tim Vroom | vroom@cs.hope.edu
| [reply] |
Re: Case insensitivity in a hash... Futile effort?
by BBQ (Curate) on Apr 18, 2000 at 23:19 UTC
|
I guess you've already considered looping? What about this:
foreach $key (keys %food_color) {
if (uc($key) eq uc($new_key)) {
$food_color{$key} = $new_value;
}
}
Of course I haven't tested this, but I don't see why it wouldn't work. With uc() you're not really ignoring case, but uppercasing everything just to make sure they match. (kinda like an SQL approach). Le'me know if that works!
Cheers!
#!/home/bbq/bin/perl
# Trust no1!
| [reply] [d/l] |
|
|
$hash{foo}{bar}{baz} = 2;
using your looping method, I'd have to loop over *three*
arrays (for the three different keys).
I'm not saying you're wrong--I'm just saying that the tie
method is, in most cases, a much better and more general
solution. | [reply] [d/l] |
|
|
I was going to say I wasn't looping through the hash, but then I went back and looked at the code because I thought... "How could it be working?" And I am. The hash won't be too terribly large for this application maybe 200 records. I guess it's time to learn to use tie.
Your humble servant, -Chuck
| [reply] |
|
|
Thank you Thank you Thank you Thank you Thank you Thank you Thank you Thank you
This was enough to take care of my issue.
Your humble servant,
-Chuck
| [reply] |
|
|
Chuck,
1. You're more than welcome (x8)! :o)
2. Btrott has a VERY good point! If you're dealing with a big hash you could get slugish in NO time.
But then again, (I shall say this perl style)
if (you're running a big hash) {
it's probably because you're pulling
something off from a text file;
if (that's true) {
then your text file shouldn't be
too big anyway;
} else {
its going to get slugish from the
filesystem access in the first place!;
}
} else {
you should be considering a comercial
database product, under which you wouldn't
need to do case detection on your hash;
}
Was that reasonably readable? In any case, I'm glad I could be of assistance!
Cheers again!
| [reply] [d/l] |
Re: Case insensitivity in a hash... Futile effort?
by btrott (Parson) on Apr 18, 2000 at 23:08 UTC
|
Well, first of all, redefining the hash *would* get rid
of Apple => red, but that's probably not what you meant. :)
In a thread a while back, vroom wrote a nice solution
using tie: Re: case sensitivity in hashes.
You'll have to modify it a bit, because you want multi-
dimensional hashes; so I think you'd probably just have
to tie all of the hashes of hashes of hashes, etc.
So, for example, say you're using vroom's
Tie::CaseInsensitive:
use strict;
my %HASH;
use Tie::CaseInsensitive;
tie %HASH, 'Tie::CaseInsensitive';
$HASH{BoB} = 1;
$HASH{bob} = 2;
$HASH{BOb} = 3;
tie %{$HASH{bill}}, 'Tie::CaseInsensitive';
$HASH{bill}{jones} = 3;
$HASH{BILL}{JONES} = 2;
use Data::Dumper;
print Dumper \%HASH;
You should get:
$VAR1 = {
'bill' => {
'jones' => 2
},
'bob' => 3
};
which looks quite right. | [reply] [d/l] [select] |
|
|
So to tie a hash four dimensional hash, I would:
$level1 = "LEVEL1";
$level2 = "LEVEL2";
$level3 = "LEVEL3";
$setting1 = "level1";
$setting2 = "level2";
$setting3 = "level3";
use Tie::CaseInsensitive;
tie %{$HASH{$level1}{$level2}{level3}}, 'Tie::CaseInsensitive';
$HASH{$level1}{$level2}{level3} = 3;
$HASH{$setting1}{$setting2}{setting3} = "Three";
use Data::Dumper;
print Dumper \%HASH;
I tried to run this code and got the following error:
Can't locate Tie/CaseInsensitive.pm in @INC at ./hashTieTest.pl line 12.
I'm guessing this means that I need to add a .pm .
but which one? Is there a tie.pm? I'll go check CPAN.
-Chuck | [reply] [d/l] |
|
|
Tie::CaseInsensitive can be gotten here:
Re: case sensitivity in hashes.
Just copy and paste it into your editor, save it, then
put it somewhere in your @INC as Tie/CaseInsensitive.pm.
And w/ a multi-dimensional hash, you need to tie each
level of the hash. Does that make sense? So you tie the
hash %HASH, then you tie $HASH{level1}, and so on down.
| [reply] |
|
|
|
|
|
|
RE: Case insensitivity in a hash... Futile effort?
by japhy (Canon) on Apr 19, 2000 at 06:23 UTC
|
Here's a Tie module you can use to recursively implement the
Tie::CaseInsensitive module on hash values that are hash
references (so you don't need to keep tie()ing).
package Tie::RecursiveCI;
use strict;
use Tie::CaseInsensitive;
use vars qw( @ISA );
@ISA = qw( Tie::CaseInsensitive );
sub STORE {
my ($self, $key, $value) = @_;
$self->{lc $key} = $value;
if (UNIVERSAL::isa($value,'HASH')) {
tie %{ $self->{lc $key} }, 'Tie::RecursiveCI';
}
return $self->{lc $key};
}
Here's a sample program using it:
#!/usr/bin/perl
use Tie::RecursiveCI;
tie %hash, 'Tie::RecursiveCI';
$hash{foo} = 10;
$hash{Foo} = 20;
$hash{bar}{blat} = 30;
$hash{BAR}{blAT} = 40;
for (sort keys %hash) {
print "$_ => $hash{$_}\n";
}
for (sort keys %{ $hash{bAr} }) {
print "$_ => $hash{bar}{$_}\n";
}
And here's the output:
bar => HASH(0xd67b0)
foo => 20
blat => 40
| [reply] [d/l] [select] |
Re: Case insensitivity in a hash... Futile effort?
by IndyZ (Friar) on Apr 19, 2000 at 06:28 UTC
|
Of course, by far the easiest option is to lc() your keys before you insert them, and before you perform lookups in the hash...
Brian | [reply] [d/l] |
|
|
Heh, then look at this :)
%hash = map
+(++$i % 2 ? lc($_) : $_),
(foo => 'bar', This => 'that', THESE => 'those');
Nifty-ish, I think. | [reply] [d/l] |
|
|
WHOA!
Care to explain? I'm not even an acolyte yet! As a matter of fact, I've gotta go to perlfunc and see what this map guy does... :o)
Cheers!
| [reply] |
|
|