Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
I have many 3 item groupings (i.e. US,USA,USD) and
I'd like to maintain a data structure in which given one I can easily write small functions to convert between the other two. I have been playing around with a few data structures, mainly:
my %countryMap = ( US => [USA,USD],...);
and
my $countryMap = { US => {country=>USA, currrency=>USD}, ... };
with these data structures, I can't seem to figure
out a way to convert from USA to US and USD to US.
can anyone help? thanks.
Re: data structure problem
by Zaxo (Archbishop) on Jun 06, 2002 at 21:45 UTC
|
From your statement of the problem, it sounds like all the codes are unique. That allows you to use a translation hash. Lets set one up starting with an Array-of-Arrays that is built directly from your data.
my @code_data = [
['US','USA','USD'],
# ...
];
my %translator = map { $_->[0] => $_,
$_->[1] => $_,
$_->[2] => $_
} @code_data;
use constant ccode => 0;
use conatant country => 1;
use constant currency => 2;
print $translator{USA}[currency];
print $translator{USD)[ccode];
You have a problem with the design which will make this construction fail as it is. What country is supposed to come back when you say $translator{EURO}[country]? Your question does not hold up on meeting real data.
The currency elements need to hash to an array. You may have other data with similar properties. It doesn't have to be painful, but it's not as simple as above: # construct %translator as before, but only for unique keys
for (@code_data) {
push @{$translator{$_->[currency]}}, $_;
}
That makes your lookups a little more complicated, but that is dictated by the problem domain.
After Compline, Zaxo | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: data structure problem
by Anonymous Monk on Jun 06, 2002 at 20:59 UTC
|
How about a two level hash representing conversions? A little
redundancy, but convenient access.
my %convert = (
to_currency => { US => 'USD',
USA => 'USD',
MR => 'MRD',
MARS => 'MRD',
},
to_country => { US => 'USA',
USD => 'USA',
MR => 'MARS',
MRD => 'MARS',
},
to_code => { USA => 'US',
USD => 'US',
MARS => 'MR',
MRD => 'MR',
},
);
my $code = 'US';
print "$code currency is: $convert{to_currency}{$code}\n";
print "$code country is: $convert{to_country}{$code}\n";
my $currency = 'USD';
print "Code for $currency is: $convert{to_code}{$currency}\n";
my $country = 'MARS';
print "$country currency is: $convert{to_currency}{$country}\n";
| [reply] [Watch: Dir/Any] [d/l] |
Re: data structure problem
by jwest (Friar) on Jun 06, 2002 at 21:03 UTC
|
Presupposing that 'country' and 'currency' will always be unique keys (and renaming your old %countryMap to %codeMap because the label made more sense to me in this case), this would work...
my %codeMap = ( US => { country => 'USA', currency => 'USD'} );
my %currencyMap = map { $codeMap{$_}{currency} => $_ } keys(%codeMap);
my %countryMap = map { $codeMap{$_}{country} => $_ } keys(%codeMap);
But, you probably want to use a database for this.
Hope this helps!
--jwest
-><- -><- -><- -><- -><-
All things are Perfect
To every last Flaw
And bound in accord
With Eris's Law
- HBT; The Book of Advice, 1:7
| [reply] [Watch: Dir/Any] [d/l] |
Re: data structure problem
by George_Sherston (Vicar) on Jun 06, 2002 at 22:07 UTC
|
Another Way To Do It - an array_ref of hashes:
$countryMap = [
{
shortcountry => 'US',
country => 'USA',
currency => 'USD',
},
{
shortcountry => 'D',
country => 'Germany',
currency => 'DM',
},
....
];
This is basically a flatfile db in memory - and can be easily saved to a file using Data::Dumper. The problem is getting the data out. I don't see a single step way to do this, but hey, we're optimising for developer time here, not cpu / memory. I'd do
sub getem {
my $data = shift;
my $find = shift;
my $in = shift;
my $return = shift;
for (@$data) {
if ($_->{$in} eq $find) {
return $_->{$return};
}
}
}
Then to find 'US' with 'USA',
my $result = getem($countryMap,'US','country','shortcountry');
§ George Sherston | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: data structure problem
by Stegalex (Chaplain) on Jun 06, 2002 at 23:22 UTC
|
Just writing to make you aware of a module called Locale::Country which is available on CPAN. This module keeps track of the official currency and country abbreviations outlined in ISO-3166. It's worth a look
~~~~~~~~~~~~~~~
I like chicken. | [reply] [Watch: Dir/Any] |
Re: data structure problem
by Abigail-II (Bishop) on Jun 07, 2002 at 11:58 UTC
|
If you were to store this in a relational database, you could just
dump it in a table and build three indices on top of it. Well, we
can do something similar in Perl (except that our indices are not
at all suitable for range queries), using hashes for the indices.
Here's some example code (assuming the codes and countries
are unique, but currencies aren't).
#!/usr/bin/perl -w
use strict;
use warnings 'all';
my (%code, %country, %currency);
while (<DATA>) {
my $info = [split];
$code {$info -> [0]} = $info;
$country {$info -> [1]} = $info;
push @{$currency {$info -> [2]}} => $info;
}
sub info_by_code {
my $code = shift;
$code {$code}
}
sub info_by_country {
my $country = shift;
$country {$country}
}
sub info_by_currency {
my $currency = shift;
@{$currency {$currency}}
}
print "Code for Germany is ", info_by_country ("GER") -> [0], "\n";
print "People pay in Euros in ",
join (", " => map {$_ -> [1]} info_by_currency ("EUR")), "\n";
__END__
US USA USD
CA CAN CND
DE GER EUR
IT ITA EUR
FR FRA EUR
NL NET EUR
BE BEL EUR
CH SWI SFR
$ ./countries
Code for Germany is DE
People pay in Euros in GER, ITA, FRA, NET, BEL
$
Abigail
| [reply] [Watch: Dir/Any] [d/l] |
Re: data structure problem
by robobunny (Friar) on Jun 06, 2002 at 21:01 UTC
|
you could build three hashes :) otherwise, i don't think you are going to get away from painful searching. or you could use a relational database, but that seems like a bit much... | [reply] [Watch: Dir/Any] |
|
|