Introduction
Sometimes you have data with a 1:1 relationship that you put into a Hashtable
, use for awhile, and later realize you need to look up the keys from the values in the table. This article introduces a class to solve this problem.
Background
The brain-dead solution is to have two hashtables (one forward, one backward), and add everything into both. This is a bit of a pain; why not have a class to manage this, and save ourselves from redundant typing? After having this problem a couple of times, I resolved to not type things in twice, anymore. Enter BidirHashtable
, a bidirectional Hashtable
.
Using the code
BidirHashtable
is easy to create, though it doesn't support the rich set of constructors that Hashtable
does.
BidirHashtable bh = new BidirHashtable();
The interface to BidirHashtable
is essentially identical to that of Hashtable
, except that internally it is managing two Hashtable
objects. For example:
bh[1] = 101;
bh[2] = 102;
Caveat: You'll want to make sure only to use a 1:1 relationship. While 1:n relationships are impossible to establish with Hashtable
or BidirHashtable
, n:1 relationships are possible with Hashtable
. BidirHashtable
, however, is not designed with n:1 in mind, because for BidirHashtable
it means a 1:n relationship for the reverse table--patently impossible. So be warned--and don't try it.
bh[1] = 101;
bh[2] = 101;
Checking whether elements are in the table is easy:
System.Diagnostics.Debug.Assert( bh.Contains(1) );
System.Diagnostics.Debug.Assert( bh.ContainsValue(101) );
Note the ContainsValue()
function. This is in Hashtable
, but in BidirHashtable
, it is actually faster, as it does its lookup using the reverse table.
Forward lookups are also as in Hashtable
:
System.Diagnostics.Debug.Assert( (int) bh[1] == 101 );
Reverse lookups, however, are new:
System.Diagnostics.Debug.Assert( (int) bh.ReverseLookup(101) == 1 );
For ease of use and efficiency, BidirHashtable
also supports some conversions and additional ways to construct. For example:
public BidirHashtable(IDictionary dict)
This constructor takes a Hashtable
or other IDictionary
, and initializes the BidirHashtable
from it.
Explicit casts are built in for both directions. Be warned, they result in the source object being cloned for the destination object. Still, they make using BidirHashtable,
even easier:
Hashtable ht = (Hashtable) bh;
BidirHashtable bh2 = (BidirHashtable) ht;
This function creates a new BidirHashtable
which is attached to the input Hashtable
. Be careful in using it, but it can be a useful optimization:
public static BidirHashtable Attach(Hashtable ht)
If for any reason, you want the directions swapped, it's just a matter of swapping the internal Hashtable
objects. This function accomplishes that:
public void ReverseDirection()
BidirHashtable
implements IDictionary
, ICollection
, IEnumerable
, and ICloneable
. It does not (yet) implement ISerializable
, though it could be added eventually.
Points of interest
Writing this class was one of those rare circumstances where, once it compiled, it basically worked. I did add a few things after the fact, but it's a simple class. You can find more information on my website.
History
- 08-30-2003 - 1.0 - Initial revision