Simple version using a variant of memoization
While part of the answer I was going to give was already posted by Istvan, I will still post mine since the self-precomputing part was not part of Istvan's answer. The following will use the variant of memoization to precompute the dispatch table:
ClearAll[elem]; elem[chem_, element_] := With[{dispatchTable = Dispatch[Thread[ elements -> chem]]}, elem[chem, el_] := el /. dispatchTable; elem[chem, element]];
What happens here is that the general new definition is created upon the first call with a given property, and then that more specific definition is used:
elem[chemistry, "C"] (* 0.032 *)
Making a function generator
One flaw of the above answer is that the function elem depends on a global variable elements, in a rather non-transparent way. A better way would be to make a function generator:
ClearAll[makeElem]; makeElem[elemName_Symbol, elements_] := elemName[chem_, element_] := With[{dispatchTable = Dispatch[Thread[ elements -> chem]]}, elemName[chem, el_] := el /. dispatchTable; elemName[chem, element]];
In this case, everything is local. One can now generate the elem function as
Clear[elem]; makeElem[elem, elements]
and then use it as before:
elem[chemistry, "C"] (* 0.032 *)
Making this object-oriented
While the function generator is a better answer than the simple version, it may have a problem in that you have to come up with a name of the function elem - while this function is intimately tied with the particular set of elements. This calls for an OO approach, where it will be encapsulated in an instance (object), which will be created from a given list of elements. Here I will show how one can do this using an object-oriented extension I have proposed some time ago.
First, to try it, you have to execute
Import["https://gist.github.com/lshifr/4266126/raw/OO.m"]
which will load the OO package. Here is then a possible way to do what we want:
DeclareType[ChemicalElement][ OO`Methods`new[elements_List] := Module[{elem}, $self@AddMethods[ OO`Methods`addProperty[prop_] := Module[{dispatchTable = Dispatch[Thread[ elements -> prop]]}, $self@AddMethods[ OO`Methods`get[prop, el_] := el /. dispatchTable ] ] ]; $self ] ];
It is perhaps a bit more complex than it needs be, since some of the mechanisms of the current OO` implementation are not perfect. What is done here is that I declared a type ChemicalElement with a new method. This method, when called, constructs an instance of ChemicalElement type and adds a new method addProperty (this is possible because the object model of OO` is flexible enough to be able to add methods on per-instance basis at run-time - which is e.g. not possible in Java but possible in Javascript).
Whenever you want to add a new property to your object, you call addProperty. So, here is our example:
ch = ChemicalElement[{}] @ new[elements] (* « ChemicalElement[]» *)
Now we add the property chemistry:
ch @ addProperty[chemistry]
and now we can use it:
ch@get[chemistry,"C"] (* 0.032 *)
If you then need to add another property (for example, and index of a given element), you can do it:
index = Range[Length[elements]]; ch@addProperty[index]
and now you can use it too:
ch@get[index,"C"] (* 1 *)
One remaining flaw is that the properties are associated with specific values of specific variables (chemistry and index here). This can be easily changed by using some e.g. string names and changing the signature of addProperty accordingly.
Permanent installation of OO.m.
To permanently install OO` on your machine, you can use
Import["https://raw.github.com/lshifr/ProjectInstaller/master/BootstrapInstall.m"]
which will install the ProjectInstaller project into your $USerBaseDirectory/Applications, and then call
Needs["ProjectInstaller`"] ProjectInstall[URL["https://gist.github.com/4266126/download"]]
alternatively, you can use the copyRemote utility by Rolf Mertig. Note however that ProjectInstaller installs entire project, which includes not just OO.m, but also example notebook and a file with project meta-data, so I recommend using that.
TiByN="Ti"/"N"and then insert numeric values with something likeTiByN /. parameterswhereparameters = Thread[elements->chemistry](you could useDispatchfor optimization). With such an approach you can very easily control whether and when to insert values. What you do looks a little like working against the (strong parts of the) system to me... $\endgroup$