views:

210

answers:

9

What is the most efficient way to do look-up table in C#

I have a look-up table. Sort of like

0 "Thing 1"
1 "Thing 2"
2 "Reserved"
3 "Reserved"
4 "Reserved"
5 "Not a Thing"

So if someone wants "Thing 1" or "Thing 2" they pass in 0 or 1. But they may pass in something else also. I have 256 of these type of things and maybe 200 of them are reserved.

So what is the most efficient want to set this up?

  • A string Array or dictionary variable that gets all of the values. And then take the integer and return the value at that place.

One problem I have with this solution is all of the "Reserved" values. I don't want to create those redundant "reserved" values. Or else I can have an if statement against all of the various places that are "reserved" but they might now be just 2-3, might be 2-3, 40-55 and all different places in the byte. This if statement would get unruly quick

  • My other option that I was thinking was a switch statement. And I would have all of the 50ish known values and would fall through through and default for the reserved values.

I am wondering if this is a lot more processing than creating a string array or dictionary and just returning the appropriate value.

  • Something else? Is there another way to consider?
+7  A: 

"Retrieving a value by using its key is very fast, close to O(1), because the Dictionary(TKey, TValue) class is implemented as a hash table."

var things = new Dictionary<int, string>();
things[0]="Thing 1";
things[1]="Thing 2";
things[4711]="Carmen Sandiego";
Jonas Elfström
+2  A: 

If you have lots of reserved (currently unused) values or if the range of the integer values can get very big, then I would use a generic dictionary (Dictionary):

var myDictionary = new Dictionary<int, string>();
myDictionary.Add(0, "Value 1");
myDictionary.Add(200, "Another value");
// and so on

Otherwise, if you have a fixed number of values and only few of the are currently unused, then I'd use a string array (string[200]) and set/leave the reserved entries to null.

var myArray = new string[200];
myArray[0] = "Value 1";
myArray[2] = "Another value";
//myArray[1] is null
M4N
A: 

The in-built Dictionary object (preferably a generic dictionary) would be ideal for this, and is specifically designed for fast/efficient retrieval of the values relating to the keys.

From the linked MSDN article:

Retrieving a value by using its key is very fast, close to O(1), because the Dictionary<(Of <(TKey, TValue>)>) class is implemented as a hash table.

As far as your "reserved" keys go, I wouldn't worry about that at all if we're only talking about a few hundred keys/values. It's only when you reach tens, maybe hundreds of thousands of "reserved" keys/values that you'll want to implement something more efficient.

In those cases, probably the most efficient storage container then would be an implementation of a Sparse Matrix.

CraigTP
A: 

I'm not quite sure I understand your problem correctly. You have a collection of strings. Each string is associated to an index. The consumer requests gives an index and you return the corresponding string, unless the index is reserved. Right?

Can't you simple set reserved items as null in the array.

If not, using a dictionary that doesn't contain the reserved items seems a reasonable solution.

Anyway, you'll probably get better answers if you clarify your problem.

Serge - appTranslator
A: 

Load all your values into

var dic = new Dictionary<int, string>();

And use this for retrieval:

string GetDescription(int val)
{
     if(0 <= val && val < 256)
        if(!dic.Contains(val))
           return "Reserved";
        return dic[val];
    throw new ApplicationException("Value must be between 0 and 255");
}
Manu
A: 

I would use a Dictionary to do the lookups. This is the most efficient way to do look ups by far. Using a string will run somewhere in the region of O(n) to find the object.

It might be useful to have a 2nd Dictionary to all you to do a reverse lookup if its needed

AutomatedTester
+2  A: 

Checkout the HybridDictionary. It automatically adjusts it's underlying storage mechanism based on size to get the greatest efficiency.

http://msdn.microsoft.com/en-us/library/system.collections.specialized.hybriddictionary.aspx

Corey Coogan
HybridDictionary is not strongly-typed/generic (everything in the collection is stored as an object), which might result in a lot of type-casting (unless you create a wrapper around it).
M4N
Very cool class I did not know about. MSDN states that the "class is recommended for cases where the number of elements in a dictionary is unknown." Seems like Maestro1024 knows the number of elements so I would guess Maestro1024 should pick between a Hashtable and ListDictionary.
Eddie
+1  A: 

The absolute fastest way to do lookups of integer values in C# is with an array. This will be preferable to using a dictionary, maybe, if you are trying to do tens of thousands of lookups at a time. For most purposes, this is overkill; it's more likely that you need to optimize developer time than processor time.

If the reserved keys are not simply all keys that aren't in the lookup table (i.e. if a lookup for a key can return the found value, a not-found status, or a reserved status), you'll need to save the reserved keys somewhere. Saving them as dictionary entries with magic values (e.g. the key of any dictionary entry whose value is null is reserved) is OK unless you write code that iterates over the dictionary's entries without filtering them.

A way to solve that problem is to use a separate HashSet<int> to store the reserved keys, and maybe bake the whole thing into a class, e.g.:

public class LookupTable
{
   public readonly Dictionary<int, string> Table { get; }
   public readonly HashSet<int> ReservedKeys { get; }

   public LookupTable()
   {
      Table = new Dictionary<int, string>();
      ReservedKeys = new HashSet<int>();
   }

   public string Lookup(int key)
   {
      return (ReservedKeys.Contains(key))
         ? null
         : Table[key];
   }
}

You'll note that this still has the magic-value issue - Lookup returns null if the key is reserved, and throws an exception if it's not in the table - but at least now you can iterate over Table.Values without filtering magic values.

Robert Rossney
A: 

Your question seems to imply that the query key is an integer. Since you have at most 256 items, then the query key is in the range 0..255, right? If so, just have a string array of 256 strings, and use the key as an index into the array.

If your query key is a string value, then it's more like a real lookup table. Using a Dictionary object is simple, but if you're after raw speed for a set of as few as 50 or so actual answers, a do-it-yourself approach such as binary search, or a trie, could be quicker. If you use binary search, since the number of items is so small, you could unroll it.

How often does the list of items change? If it only changes very seldom, you can get even better speed by generating code to do the search, which you can then compile and execute to do each query.

On the other hand, I assume you've proven that this lookup is your bottleneck, either by profiling or taking stackshots. If less than 10% of time-when-slow is spent in this query, then it is not your bottleneck so you may as well do the thing that is easiest to code.

Mike Dunlavey