Re: Ignore Case when comparing Hash Keys
by ELISHEVA (Prior) on Nov 15, 2010 at 19:12 UTC
|
exists can only do case sensitive comparisons. Instead of doing exists, extract the keys from both hashes using keys, and then lower case them both before comparison:
Note: this solution preserves the case in both hashes by storing keys in a temporary third hash.
# make temporary hash using lower case keys only
# hash allows for fast lookup of matching key later on in
# our for loop
my %hashLowercaseKeys1 = ( map { lc($_) => 1 } keys %hash1 );
foreach my $k (keys %hash2) {
if (exists $hashLowercaseKeys1{lc($k)}) {
print "$k: matched\n";
} else {
print "$k: no match\n";
}
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Thanks a lot. This works.
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by JavaFan (Canon) on Nov 15, 2010 at 18:55 UTC
|
Your description talks about comparing values, but your code doesn't. Also, comparing keys while ignoring case doesn't make the matching unique. What should the output be if
%hash1 = ("John", 43, "jOHn", 42, "JOHN", 41);
%hash2 = ("john", 42);
| [reply] [Watch: Dir/Any] [d/l] |
|
Thanks you for your response.
You are right. But I am not comparing names in my code but I am comparing the Config attributes where we will always have unique names.
For simplicity I just put the names in the example above.
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by ctilmes (Vicar) on Nov 15, 2010 at 19:15 UTC
|
When you transform the keys to lowercase for a case-insensitive lookup, keep the old name around for printing later.
#! /usr/bin/perl
%hash1 = ("John", 43, "Paul", 25, "Marie", 22);
%hash2 = ("john", 43, "Paul", 25, "marie", 22);
my %lc_hash1 = map { lc $_ => { name => $_,
value => $hash1{$_} }
} keys %hash1;
while (($KEY_2, $VALUE_2) = each %hash2){
if (exists $lc_hash1{lc $KEY_2}){
print "$KEY_2 : Matched\n";
}
else{
print "$KEY_2 : Did not match\n";
}
}
Now you can use $lc_hash1{$SOMEKEY}{name} for the original key and $lc_hash1{$SOMEKEY}{value} for the value.
| [reply] [Watch: Dir/Any] [d/l] |
|
Or just store the original key as the value of the canonicalized (lower-cased) hash. Look up in the lower case hash to find the key, then use the value of that hash to look up the value in the original hash.
#! /usr/bin/perl
%hash1 = ("John", 43, "Paul", 25, "Marie", 22);
%hash2 = ("john", 43, "Paul", 25, "marie", 22);
my %lc_hash1 = map { lc $_ => $_ } keys %hash1;
while (($KEY_2, $VALUE_2) = each %hash2){
if (exists $lc_hash1{lc $KEY_2}){
print "$KEY_2 : Matched\n";
print "Keys are: $lc_hash1{lc $KEY_2}, $KEY_2\n";
print "Values are: $hash1{$lc_hash1{lc $KEY_2}}, $VALUE_2\n";
}
else{
print "$KEY_2 : Did not match\n";
}
}
| [reply] [Watch: Dir/Any] [d/l] |
|
ctilmes --- Thanks a lot. This works great!!! Just the way I want it to. You saved me a ton of time.
Thankyou all.
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by moritz (Cardinal) on Nov 15, 2010 at 18:40 UTC
|
my %lc1 = %hash1.keys>>.lc Z %hash1.values;
for %hash2.keys -> $k {
say "$k ", %lc1.exists($k) ?? 'Matched' !! 'Did not match';
}
Transforming the code to Perl 5 shouldn't be too hard.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I cant convert the Hash Keys to lower case, because I want to display the Keys and Values Side by side in the output and I want to keep the original Case of the Keys. I was wondering if there is something like if ($a =~ /$search/i) kind of comparison that ignores the case and matches the keys. Also I want the hash to give me the value of the key
| [reply] [Watch: Dir/Any] |
|
%hash1 = ("John", 43, "Paul", 25, "Marie", 22);
%hash2 = ("john", 43, "Paul", 25, "marie", 22);
while (($KEY_2, $VALUE_2) = each %hash2){
if (grep { m/$KEY_2/i } keys %hash1) {
print "$KEY_2 : Matched\n";
}
else{
print "$KEY_2 : Did not match\n";
}
}
Note: Untested, you can keep all the bits when it breaks, etc.
...roboticus
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
I cant convert the Hash Keys to lower case, because I want to display the Keys and Values Side by side in the output and I want to keep the original Case of the Keys.
Then use another hash that maps lower case key to the correctly cased key.
Also note that the original hash with the correctly cased keys still exists, and stands at your disposal.
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by toolic (Bishop) on Nov 15, 2010 at 19:14 UTC
|
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by raybies (Chaplain) on Nov 15, 2010 at 19:27 UTC
|
I'd create a translate key hash (called %xl8 in code example below).
%hash1 = ("John", 43, "Paul", 25, "Marie", 22);
%hash2 = ("john", 43, "Paul", 25, "marie", 22);
foreach (keys %hash1) { $xl8{lc $_} = $_; }
while (($KEY_2, $VALUE_2) = each %hash2){
if (exists $xl8{lc $KEY_2}){
print "$KEY_2 : Matched\n";
}
else{
print "$KEY_2 : Did not match\n";
}
}
(looks like I was too slow... someone else suggested same with the elegant "map" solution. :) | [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
Re: Ignore Case when comparing Hash Keys
by aquarium (Curate) on Nov 15, 2010 at 21:53 UTC
|
i think you want to avoid anomalies, such as one of the hashes having multiple same values once upper/lower-cased, e.g. McGirk and Mcgirk...which would break under current arrangements. might be an idea to have the hashes keyed by lowercase/uppercase, but also store original print/visual/mixed-case value as part of the hashes.
the hardest line to type correctly is: stty erase ^H
| [reply] [Watch: Dir/Any] |