Greetings,
I am cautiously wading my way into the ocean of Mata class programming, so my apologies if I’m off on a completely wrong approach to the problem I describe below, and/or conveying too much detail on my process.
As part of a larger project, I'm creating a set of helper functions that convert among different country identifiers: names, 2-character ISO codes, 3-character ISO codes, numeric ISO codes (all based on ISO3166), and "safenames," which are no-whitespace, ASCII-only versions of the country names.
I begin with a csv file containing the codes for each country (iso_name_translation_witha3.csv):
I create a set of class AssociativeArray from the csv and save them to a file (country_iso_map.mox) by running make_country_iso_AA:
I can then load those AssociativeArrays:
And they work as I expect:
Then I include include those AssociativeArray instances (Country, Alpha2, Alpha3, Safename, and ISO) as static members of a class that also contains member functions for translation among the identifiers. I can achieve this by reading in the country_iso_map.mox file when the class is instantiated, though this feels inefficient:
Finally, I create a Mata library with the do-file make_lscaleset.do
And I can use my helper functions:
So this does work, however, two things bother me:
1. Is there a way to store the compiled AssociativeArray instances in the Mata library, so they don't have to be read from a separate file?
2. This is inefficient because I am creating five AssociativeArrays with identical contents--only the keys vary. Surely there is a better way--maybe involving pointers, which are only barely beginning to make sense for me.
Anyway, thank you for reading this far!
I am cautiously wading my way into the ocean of Mata class programming, so my apologies if I’m off on a completely wrong approach to the problem I describe below, and/or conveying too much detail on my process.
As part of a larger project, I'm creating a set of helper functions that convert among different country identifiers: names, 2-character ISO codes, 3-character ISO codes, numeric ISO codes (all based on ISO3166), and "safenames," which are no-whitespace, ASCII-only versions of the country names.
I begin with a csv file containing the codes for each country (iso_name_translation_witha3.csv):
Code:
name,alpha2,iso,safename,alpha3 Afghanistan,AF,4,Afghanistan,AFG Albania,AL,8,Albania,ALB Antarctica,AQ,10,Antarctica,ATA Algeria,DZ,12,Algeria,DZA . . Côte d’Ivoire,CI,384,CotedIvoire,CIV . .
I create a set of class AssociativeArray from the csv and save them to a file (country_iso_map.mox) by running make_country_iso_AA:
Code:
program make_country_iso_AA
clear
// import, forcing iso to string
import delimited using iso_name_translation_witha3.csv, stringcols(_all)
capture erase country_iso_map.mox
mata:doit()
// demonstrate the AssociativeArrays work as expected:
mata: Alpha3.get("CIV")
end
version 18.0
mata:
mata set matastrict on
void doit()
{
class AssociativeArray scalar Country, Alpha2, Alpha3, Safename, ISO
string matrix X
X = st_sdata( . , ("name", "alpha2", "alpha3", "safename", "iso") )
for (i=1; i<=rows(X); i++) {
Country.put( X[i,1] , (X[i,.]) )
Alpha2.put( X[i,2] , (X[i,.]) )
Alpha3.put( X[i,3] , (X[i,.]) )
Safename.put( X[i,4] , (X[i,.]) )
ISO.put( X[i,5] , (X[i,.]) )
}
fh = fopen("country_iso_map.mox", "w")
fputmatrix(fh, Country)
fputmatrix(fh, Alpha2)
fputmatrix(fh, Alpha3)
fputmatrix(fh, Safename)
fputmatrix(fh, ISO)
fclose(fh)
}
end
Code:
clear *
mata
fh = fopen("country_iso_map.mox", "r")
Country =fgetmatrix(fh)
Alpha2 =fgetmatrix(fh)
Alpha3 =fgetmatrix(fh)
Safename =fgetmatrix(fh)
ISO =fgetmatrix(fh)
fclose(fh)
Code:
: Alpha3.get("CIV")
1 2 3 4 5
+---------------------------------------------------------------------------------+
1 | Côte d’Ivoire CI CIV CotedIvoire 384 |
+---------------------------------------------------------------------------------+
: ISO.get("384")
1 2 3 4 5
+---------------------------------------------------------------------------------+
1 | Côte d’Ivoire CI CIV CotedIvoire 384 |
+---------------------------------------------------------------------------------+
Code:
*! version 1.0.0 scale_set_utility_functions.mata
version 18
mata:
class countryConverter
{
static class AssociativeArray scalar Country, Alpha2, Alpha3, Safename, ISO
void new()
real scalar isoofname()
string scalar a2ofname(), a3ofname(), safenameofname()
}
void countryConverter::new() {
// only need to load AAs once b/c static
if (!Country.N() ) {
display("Loading country_iso_map.mox")
// todo: put country_iso_map.mox on adopath so we can find it
fh = fopen("country_iso_map.mox", "r")
Country =fgetmatrix(fh)
Alpha2 =fgetmatrix(fh)
Alpha3 =fgetmatrix(fh)
Safename =fgetmatrix(fh)
ISO =fgetmatrix(fh)
fclose(fh)
}
}
string scalar countryConverter::a2ofname(string scalar countryname)
{
return (this.Country.get(countryname)[1,2])
}
string scalar countryConverter::a3ofname(string scalar countryname)
{
return (this.Country.get(countryname)[1,3])
}
string scalar countryConverter::safenameofname(string scalar countryname)
{
return (this.Country.get(countryname)[1,4])
}
real scalar countryConverter::isoofname(string scalar countryname)
{
return ( strtoreal(this.Country.get(countryname)[1,5]) )
}
end
Code:
*! make_lscaleset.do // version number intentionally omitted clear all do "scale_set_utility_functions.mata" lmbuild lscaleset.mlib, replace
Code:
. mata
------------------------------------------------- mata (type end to exit) -------------------------------------------
: cc=countryConverter()
Loading country_iso_map.mox
: cc2=countryConverter()
: cc2.a3ofname("Côte d’Ivoire")
CIV
: cc2.isoofname("Côte d’Ivoire")
384
: eltype(cc2.isoofname("Côte d’Ivoire"))
real
So this does work, however, two things bother me:
1. Is there a way to store the compiled AssociativeArray instances in the Mata library, so they don't have to be read from a separate file?
2. This is inefficient because I am creating five AssociativeArrays with identical contents--only the keys vary. Surely there is a better way--maybe involving pointers, which are only barely beginning to make sense for me.
Anyway, thank you for reading this far!

Comment