views:

207

answers:

9

I have an object that I want to use to look up other objects. I will be using a Dictionary<TKey, TValue>().

The key object has two strings that uniquely identify it, say KeyObj.Str1 and KeyObj.Str2.

What do you recommend that I use as the key for the dictionary?

1: The concatenation of the strings.

Dictionary<String, TValue>();
Key = KeyObj.Str1:KeyObj.Str2; ("somestring:anotherstring")

2: A unique integer for each object to identify it?

Dictionary<int, TValue>();
KeyObj.ID = _nextID++;
Key = KeyObj.ID;

3: A reference to the object.

Dictionary<KeyObj, TValue>();
Key = KeyObj;

Option 3 would be the easiest, but it seems like it would be inefficient to index a dictionary based on reference values.

If the key object contained a single unique string, the obvious choice would be use that, but having two strings that are only unique in combination makes it more difficult.

A: 

You don't need to use a new class as the dictionary key. Using a new struct instead as it will be much more lightweight... And have it consist of those two string values obviously.

Ian
The class that I am using is more complicated that I described in the example... I simplified it to keep it clear. I don't want to make it a struct.
Josh G
A: 

If performance is a major consideration, you could consider using a hashvalue of the two strings. But then your 'value' field would have to contain both the keys and the value.

I have a reference to another SO question, I just have to find it.

http://stackoverflow.com/questions/658065/is-it-faster-to-search-for-a-large-string-in-a-db-by-its-hashcode/658187

But that question is more DB oriented. And the performance is considered for thousands of iterations.

+1  A: 

I would say option 1.

Matt Grande
+1  A: 

Concatenating them is probably the best idea. You can expose a property in the KeyObj object that does the concatenation so you don't have to perform it each time you're accessing the dictionary value.

Edit:

I apparently misread the question. I think what you really want to do is a mix of 1 and 3, you can override Equals() and GetHashCode() to use the strings that uniquely identify the object (just make sure they are immutable!)

public override Equals(object obj) 
{
   if (obj == null || !(obj is KeyObj))
      return false;
   KeyObj other = (KeyObj)obj;
   if (this.Key1 == other.Key1 && this.Key2 == other.Key2)
     return true;
   return false;
}

public override GetHashCode()
{
    return (this.Key1 + this.Key2).GetHashCode();
}

Then you can use the 3rd option you suggested:

Dictionary<KeyObj, ValueObj>...
John Rasch
+1  A: 

what about using the KeyObj.GetHashCode()?

Oscar Cabrero
This sounds promising...
Josh G
According to MSDN: The default implementation of the GetHashCode method does not guarantee unique return values for different objects.
Groo
(therefore the actual question here was how to implement it)
Groo
+1  A: 

Any of them are valid, but I'm assuming you'd want to be able to quickly find these objects based on one of the two strings, so using an int as the key would mean you'd still have to scan the values to find the object you wanted.

Are the strings both unique, or only when combined? If they're both unique, and you're willing to trade a bit of space, you could do:

dict.Add(KeyObj.Str1, KeyObj);
dict.Add(KeyObj.Str2, KeyObj);

and have two references to the object in the dictionary, using each unique string as a key. Or, you could always just combine the strings if they're only unique together, and it'll use the hashcode internally to look them up.

Chris Doggett
They are only unique when combined.
Josh G
+1  A: 

Concatenated strings should work best.

IF you know that their combination is unique, then that is what you should choose -- remember that Hash code is usually unique, but not always.

Groo
A: 

Remember that a dictionary is a glorified hash table, so the key (no pun intended) is to use a key that will result in very few (if any) collisions with another key. I'd lean toward #3, but that's assuming the KeyObj type has a good hash value generator.

WaldenL
I wouldn't say so, because all keys must be unique in a dictionary.
Groo
Does the Dictionary class implicitly use KeyObj.GetHashCode() for comparing the reference objects?
Josh G
It actually uses a default implementation of EqualityComparer<KeyObj> (if you don't specify one). It uses the GetHashCode result to speed up the search (by creating several buckets), but at the end it uses the Equals method to make sure that they are identical.
Groo
+2  A: 

You could use option 3 if you can override GetHashCode() and Equals() appropriately, i.e. something like this:

    public override int GetHashCode()
    {
        return str1.GetHashCode() ^ str2.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        if (!obj is KeyObj)
        {
            return false;
        }

        KeyObj key = (KeyObj)obj;
        return this.str1.Equals(key.str1) && this.str2.Equals(key.str2);
    }
Benjamin Cutler
This is a good option for making #3 work. Thanks.
Josh G