in reply to Re^2: Check if key exist in hash but not exact match
in thread Check if key exist in hash but not exact match
I tinkered some more:
There was a bug which I've fixed. I've no idea why, but I'd coded for only one NO_CASE. Obviously, you can have ABC, Abc, abc, AbC, and so on.
I decided that I was doing too much work with @matches. I changed that to %matches and, instead of removing elements from the array by recreating it using grep, I'm simply using delete to remove key/value pairs. This resulted in much cleaner code and, I imagine, would be a lot more efficient.
There was also an interesting point regarding the contents of the "Value" column produced by printf. Having introduced undef values in my test data for basic edge-case checks, this meant that there was either a price (number) or '<undefined>' (string). A %s worked fine for both when the price was 1.25; however, a price of 3.00 was converted to just 3.
My introduction of undef may have been completely artificial and would never occur in the OP's data: in this case, a %.2f would probably suffice throughout. I've left the undef values as it was an interesting exercise dealing with this. I can see potential improvements here but won't go into that further unless it is something the OP really wants.
As before, I'll put the new code and another sample run in a spoiler.
Code:
#!/usr/bin/env perl use v5.36; use List::Util 'max'; my %price = ( 'Coca Cola' => 1.25, coke => 1.25, COLA => 1.25, Cola => 1.25, cola => 1.25, 'Pepsi Cola' => 1.25, pizza => 12.00, sandwich => 3.00, 'UNDEAD COLA' => undef, 'Undead Cola' => undef, 'Undead cola' => undef, 'undead cola' => undef, ); say 'Enter whole or partial name for key (just hit Return to exit).'; while (1) { print "\nName: "; my $name = <STDIN>; chomp $name; unless (length $name) { say 'Exiting ...'; last; } unless ($name =~ /^[A-Za-z0-9 ]+$/) { say 'Only alphanumeric+space name searches allowed.'; next; } check_keys(\%price, $name); } sub check_keys ($hash, $name) { my %matches = map +($_ => 1), grep /$name/i, keys %$hash; if (keys %matches) { _printf_head($hash); if (exists $matches{$name}) { _printf($hash, 'EXACT', $name); delete $matches{$name}; } } else { say "No keys match '$name'."; return; } for (grep /^$name$/i, sort keys %matches) { _printf($hash, 'NO_CASE', $_); delete $matches{$_}; } for (sort keys %matches) { _printf($hash, 'PARTIAL', $_); } return; } sub _printf ($hash, $match, $key) { my $fmt = "%-7s %-@{[max map length, keys %$hash]}s "; $fmt .= defined $hash->{$key} ? "%.2f\n" : "%s\n"; printf $fmt, $match, $key, $hash->{$key} // '<undefined>'; return; } sub _printf_head ($hash) { my $fmt = "%-7s %-@{[max map length, keys %$hash]}s %s\n"; printf $fmt, qw{Match Key Value}; printf $fmt, qw{----- --- -----}; return; }
Sample run:
Enter whole or partial name for key (just hit Return to exit). Name: cok Match Key Value ----- --- ----- PARTIAL coke 1.25 Name: col Match Key Value ----- --- ----- PARTIAL COLA 1.25 PARTIAL Coca Cola 1.25 PARTIAL Cola 1.25 PARTIAL Pepsi Cola 1.25 PARTIAL UNDEAD COLA <undefined> PARTIAL Undead Cola <undefined> PARTIAL Undead cola <undefined> PARTIAL cola 1.25 PARTIAL undead cola <undefined> Name: Coca Cola Match Key Value ----- --- ----- EXACT Coca Cola 1.25 Name: Undead Cola Match Key Value ----- --- ----- EXACT Undead Cola <undefined> NO_CASE UNDEAD COLA <undefined> NO_CASE Undead cola <undefined> NO_CASE undead cola <undefined> Name: Cola Match Key Value ----- --- ----- EXACT Cola 1.25 NO_CASE COLA 1.25 NO_CASE cola 1.25 PARTIAL Coca Cola 1.25 PARTIAL Pepsi Cola 1.25 PARTIAL UNDEAD COLA <undefined> PARTIAL Undead Cola <undefined> PARTIAL Undead cola <undefined> PARTIAL undead cola <undefined> Name: cola Match Key Value ----- --- ----- EXACT cola 1.25 NO_CASE COLA 1.25 NO_CASE Cola 1.25 PARTIAL Coca Cola 1.25 PARTIAL Pepsi Cola 1.25 PARTIAL UNDEAD COLA <undefined> PARTIAL Undead Cola <undefined> PARTIAL Undead cola <undefined> PARTIAL undead cola <undefined> Name: ^cola$ Only alphanumeric+space name searches allowed. Name: (?{/path/to/evil_code}) Only alphanumeric+space name searches allowed. Name: Nightingale Tongues in Aspic No keys match 'Nightingale Tongues in Aspic'. Name: p Match Key Value ----- --- ----- PARTIAL Pepsi Cola 1.25 PARTIAL pizza 12.00 Name: s Match Key Value ----- --- ----- PARTIAL Pepsi Cola 1.25 PARTIAL sandwich 3.00 Name: Exiting ...
— Ken
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^4: Check if key exist in hash but not exact match
by ibm1620 (Hermit) on Apr 04, 2023 at 21:36 UTC | |
by LanX (Saint) on Apr 04, 2023 at 21:51 UTC | |
by eyepopslikeamosquito (Archbishop) on Apr 04, 2023 at 22:23 UTC | |
by kcott (Archbishop) on Apr 04, 2023 at 22:41 UTC | |
by ibm1620 (Hermit) on Apr 05, 2023 at 12:11 UTC |