get original key object from dictionary

N

not_a_commie

given a Dictionary<object, object> and an object that exactly
replicates the Equals and GetHashCode of the original object used as
the dictionary key, how do I retrieve the original key that was used?
 
M

Marc Gravell

I can't see an easy way - perhaps you have to drop down to looping?
Shown in the general (TKey / TValue) terms:

TKey testKey; // our equivalent but different key

IEqualityComparer<TKey> comparer = dict.Comparer;
foreach (KeyValuePair<TKey, TValue> pair in dict) {
if (comparer.Equals(testKey, pair.Key)) {
return pair.Key; // the original (or a clone if
blittable)
}
}
throw new KeyNotFoundException();

Marc
 
M

Marc Gravell

Not sure I understand the objective here. If you used the ContainsKey method
and it returns true, you know you have it, correct?

I believe the OP means that he has two different objects (presumably
classes) that he considers equal - i.e. they represent the same
Customer, but are different instances. He intends to use the one he
has "in hand" to find the original that was used as the key in the
dictionary. Quite common when dealing with facades, flyweights, etc.

I have seen this done before, but I think I've concluded over the
years that I prefer to use primatives for keys...

Marc
 
P

Peter Duniho

I believe the OP means that he has two different objects (presumably
classes) that he considers equal - i.e. they represent the same
Customer, but are different instances. He intends to use the one he
has "in hand" to find the original that was used as the key in the
dictionary. Quite common when dealing with facades, flyweights, etc.

But doesn't Dictionary<> already handle that correctly?

Obviously for value types as keys, it does. But AFAIK it also does as
well for reference types. For example, if the key is a string, as long as
I have a string instance that is equal to the one used for the key, it
does not have to be the same string instance as that originally used as
the key.

What's in the class shouldn't matter, as long as it hashes and compares
the same as the original key.

I share Peter B.'s confusion over the question. Seems like given what the
OP's already stated, the Dictionary<> does just what he'd want, without
additional work. Either he's missing something, or Peter and I are.

Pete
 
N

Nicholas Paldino [.NET/C# MVP]

I think that the OP has an instance of a type which has other members
which don't necessarily contribute to the identity of the object being used
as a key, and he needs to retrieve those from the original key.

Which I agree really doesn't make sense, because if it is that
important, those attributes should be stored elsewhere, based on the same
key.
 
M

Marc Gravell

I share Peter B.'s confusion over the question. Seems like given what the
OP's already stated, the Dictionary<> does just what he'd want, without
additional work. Either he's missing something, or Peter and I are.

The original question was (my emph): "how do I retrieve the original
****key**** that was used?"

Using an alternative but equivalent *key* will allow you to get the
same *value*, but it won't (unless I'm being really slow) allow you
direct access to the original *key*.

My interpretation of the question, therefore, is: in the following,
and given you know only "dict" and "equivalentKey", obtain the
instance "originalKey".
The loop I provided whould do this.

Dictionary dict = ...
MyKey originalKey = ...
MyValue value = ...

dict.Add(originalKey, value);
MyKey equivalentKey = originalKey.Clone();
 
P

Peter Duniho

I believe the OP means that he has two different objects (presumably
classes) that he considers equal - i.e. they represent the same
Customer, but are different instances.

For the record, I wrote a small sample program (see below) that confirms
to the OP requirements as I understand them, and without anything extra it
"just works". I don't even have to use the same type or even a related
type when calling ContainsKey() as that used for the actual key.

I think some clarification is in order, if there's something OP is trying
to do but can't.

Pete


using System;
using System.Collections.Generic;
using System.Text;

namespace TestCustomHashDictionary
{
class Program
{
class TestClassOne
{
private string _str1;
private string _str2;

public TestClassOne(string str1, string str2)
{
_str1 = str1;
_str2 = str2;
}

public override int GetHashCode()
{
return _str1.GetHashCode() ^ _str2.GetHashCode();
}

public override bool Equals(object obj)
{
if (obj != null)
{
return ToString().Equals(obj.ToString());
}

return false;
}

public override string ToString()
{
return _str1 + _str2;
}
}

class TestClassTwo
{
private string _str;
private int _hash;

public TestClassTwo(string str1, string str2)
{
_hash = str1.GetHashCode() ^ str2.GetHashCode();
_str = str1 + str2;
}

public override int GetHashCode()
{
return _hash;
}

public override bool Equals(object obj)
{
return ToString().Equals(obj.ToString());
}

public override string ToString()
{
return _str;
}
}

static void Main(string[] args)
{
Dictionary<object, object> dict = new Dictionary<object,
object>();

dict.Add(new TestClassOne("one", "two"), null);

Console.WriteLine(
"dict.ContainsKey(new TestClassTwo(\"one\", \"two\"): "
+ dict.ContainsKey(new TestClassTwo("one", "two")));

Console.ReadLine();
}
}
}
 
P

Peter Duniho

The original question was (my emph): "how do I retrieve the original
****key**** that was used?"

Using an alternative but equivalent *key* will allow you to get the
same *value*, but it won't (unless I'm being really slow) allow you
direct access to the original *key*.

No, I think I was being slow. I didn't pick up the fact that he wanted
the original key.

While I agree with Nicholas that this may indicate a problem with the
basic design of the OP's code, it does highlight something that's bugged
me about the Dictionary<> and similar classes. That is, you can get a
collection of keys that is ordered (even if the order isn't well-defined),
and you can check for containment of a key, but you cannot get the ordinal
index of that key related to the collection, given the key.

Obviously the class itself has a fast way to do that, but it doesn't
expose it in any way as far as I know. I've seen at least two different
situations now where it'd be useful (this scenario, and a previous thread
that involved the fastest way to get an item from a Dictionary).

Anyway, thanks for the clarification. I understand the OP now (and the
misunderstanding was all mine...rereading the post, it seems fine :) ).

Pete
 
M

Marc Gravell

... something that's bugged me about the Dictionary said:
... but you cannot get the ordinal index of that key related to the collection, given the key.

Well, you can for SortedList, but that's about it... ;-(

Marc
 
P

Peter Duniho

Well, you can for SortedList, but that's about it... ;-(

Yes, but why only that one?

For SortedDictionary, I understand. The underlying implementation is a
binary tree, not an array. But the docs say that Dictionary has the same
basic behavior as SortedList (that is, the Keys collection is a wrapper
around the original data).

Not all of the collection classes would lend themselves to having an
IndexOfKey() method, but I'm not really clear on why it's not on every
class where it apparently would make sense.

Pete
 
N

not_a_commie

Yes, I suppose that looping is the only way to do it. Thanks for all
your comments. I have some objects that use Guids for their uniqueId,
their hashcode, and their equals. It's easy to make a stubbed instance
of the class and use that as a lookup for a value if all you have is a
Guid. Then you just keep a static reference to it and change the Guid
on it when you need to do a lookup by Guid. However, it didn't work
cleaning for looking up the original keys.
 
P

Peter Duniho

Yes, I suppose that looping is the only way to do it. Thanks for all
your comments. I have some objects that use Guids for their uniqueId,
their hashcode, and their equals. It's easy to make a stubbed instance
of the class and use that as a lookup for a value if all you have is a
Guid. Then you just keep a static reference to it and change the Guid
on it when you need to do a lookup by Guid. However, it didn't work
cleaning for looking up the original keys.

Well, maybe you could be more specific about why you need to retrieve the
key at all.

I'm not saying there's never a reason to, but it's not a common request.
Usually, if you're trying to use a key/value data structure (like the
Dictionary<> class) to look things up, you get the data you want from the
value.

You could just make the key the GUID and put the instances as the values.
Or you could make the instances the key and value. Or, if you already
have some value _and_ you still want to be able to quickly get the object
according to the key, you could store a struct as the value in the
dictionary that has both the GUID-based instance, as well as the value
you're currently storing in the dictionary.

In other words, while enumerating each and every key would certainly work,
it kind of defeats the purpose (I think) of using a dictionary. I think
it would make more sense to accommodate the normal usage patterns of the
dictionary, rather than shoe-horn some alternative usage into it.

Pete
 
L

Lasse Vågsæther Karlsen

not_a_commie said:
given a Dictionary<object, object> and an object that exactly
replicates the Equals and GetHashCode of the original object used as
the dictionary key, how do I retrieve the original key that was used?

One solution that would introduce some overhead could be to just have
two dictionaries, one with the key->key mapping and one with the
key->value mapping.

Another solution could be to create a simple struct that holds both the
key and value, and store this in the dictionary instead of just the
value, that way you will always have access to the original key directly.

ie.

(note, untested code, just written in the newsreader)

public struct DictionaryKeyValueWrapper<TKey,TValue>
{
public TKey OriginalKey;
public TValue Value;
public DictionaryKeyValueWrapper(TKey originalKey, TValue value)
{
OriginalKey = originalKey;
Value = value;
}
public DictionaryKeyValueWrapper()
{
OriginalKey = default(TKey);
Value = default(TValue);
}
}

then you could do:

dict[key_lookalike].OriginalKey
dict[key_lookalike].Value
 
N

not_a_commie

So I ended up with a dictionary where the key is the Guid and the
value is a KeyValuePair of the two objects I need indexed by that Guid.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top