views:

49

answers:

2

Hi all,

I have conversion tables I need to contain in memory for fast access. Until now I used a simple Hashtable were the Key was the internal code, and the Value was an object holding the external code and other meta-data.

Now we need to have a reverse look-up, meaning to get the internal code based on the external code. I could only come up with the following options:

  1. Have another container for this look-up, Hashtable containing only the internal code as Value to prevent more redundancy.
  2. Use the same container I use now, and store those objects again now using the the external code as the Key (have a prefix to prevent collisions).
  3. Don't pull data using Keys, but iterate through the Values contained under the same container to find the requested object ( O(n), same memory usage ).

The container is being lazy-loaded, so options 1&2 usually won't perform under the worst-case scenario.

Thoughts anyone? Please tell me there's some efficient container I could use for that, which I missed!

* EDIT *

Being a GC'd framework, and accepting the fact I'd have to have two conversion arrays (Dictionaries), would the following lines of code actually mean I stored only one object on memory, and then two pointers for it, under two different hashed-cells?

Dictionary<K1,V> forward;
Dictionary<K2,V> reverse;
//...    
void Add(V myObject)
{
    // myObject being the BLL object
    forward.Add(myObject.InternalCode, myObject);
    reverse.Add(myObject.ExternalCode, myObject);
}

Itamar.

A: 

I rather use two instances of Dictionary<TKey, TValue>

It favors code readability

Are you sure this dictionary is a performance bottleneck?

Jader Dias
+1  A: 

Build a custom collection class that has two internal hashtables (Dictionarys), one in each direction.

  public BiHashTable<K, V>
  {
     private Dictionary<K, V> vals = new Dictionary<K, V>();
     private Dictionary<V, K> keys = new Dictionary<V, K>();
     public void Add(K key, V val)
     {
        vals.Add(key, val);
        keys.Add(val, key);
     }
     public K this[v val] { get { return keys[val]; } }
     public V this[K key] { get { return vals[key]; } }
     // etc... 
  }

NOTE: This will be problematic is both K and V are the same type, you need a different formulation then...

Charles Bretana
Only problem with this, as explained in the question, is that V is not of a native type. I wouldn't want to use it as a key... Also, this is actually the implementation of the worst case scenario - the 2 Hashtables stored twice as a whole - exactly what I want to avoid...
synhershko
@synhershko, Why do you want to avoid this? Remember, all you are storing twice is a reference variable, a pointer. You are not storing the objects twice. And I see no way around storing something twice. If you don't, you're stuck with iterating through the single collection to find the key for a given value. And you are not storing, or "actually using" the object as a key, remember, you are actually using the hash created from the object as the key.
Charles Bretana
Yes, I figured as such - see my edit. I was asking to see if there's a way around holding two Hashtables -- apparently the answer is no. With regards to computing a hash of a non-native type, I know its a computed hash of it which is being used as a key. However, my gut tells me it won't be ideal when the object grows larger (e.g. has another array/hashtable in it) - just computing the hash would be an expensive task, at least more expensive than you'd want for live systems.
synhershko
That's why, for custom classes, you are advised to override the GetHashCode() method, to make sure that the process is efficient. Write your own that is fast, efficient. and unique.
Charles Bretana