3

Possible Duplicate:
Bidirectional 1 to 1 Dictionary in C#

Im curious if a datastructure exists in the standard .net libraries that can represent a 1-1 relationship, such as the following

1-a
4-b
6-c
5-d

Where I can say:

thisstructure[1] // returns "a"
thisstructure.GetKey["d"] // return 5

I understand all keys would have to be unique, does anything similar exist?

Thanks!

Community
  • 1
  • 1
greggorob64
  • 2,487
  • 2
  • 27
  • 55

3 Answers3

4

Yes- it's called KeyedCollection. It is intended to be subclassed and provides indexed access as well as access by a property derived from the added item. I usually make a generic subclass:

public class GenericKeyedCollection<TKey, TValue> : KeyedCollection<TKey, TValue> {

    private readonly Func<TValue, TKey> _keyGenerator;

    public GenericKeyedCollection(Func<TValue, TKey> keyGenerator) {
        _keyGenerator = keyGenerator;
    }

    protected override int GetKeyForItem(TValue item)
   {
      return _keyGenerator(item);
   }
}

To use it:

var myCollection = new GenericKeyedCollection<String, Car>(c=>c.Model);
myCollection.Add(new Car("Ford", "Mustang"));
var byIndex = myCollection[0];
var byModel = myCollection["Mustang"];

The only caveat is that the derived property (the "key") mustn't change after the item has been added.

If your key is not a property of the value, then you can use a Tuple<T1, T2> to combine the key and value:

var myCollection = new GenericKeyedCollection<String, Tuple<String, Car>>(t=>t.Item1);
myCollection.Add(new Tuple<String, Car>("Foo", Car("Ford", "Mustang")));
var byIndexCar = myCollection[0].Item2;
var byItem1Car = myCollection["Foo"].Item2;
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • Is KeyedCollection unique to .NET 4 or was it around in earlier versions? – Nevyn Jul 25 '12 at 19:46
  • Can this be adopted to solve the OP's problem? It does not look like in the OP's case a key can be extracted from the value, which appears to be the requirement for `KeyedCollection`. – Sergey Kalinichenko Jul 25 '12 at 19:47
  • @dasblinkenlight if the OP's value can be a `Tuple` then yes. I'll add that to the explanation. – Chris Shain Jul 25 '12 at 19:48
  • @Nevyn been there since 2.0 according to the docs. – Chris Shain Jul 25 '12 at 19:49
  • Learn something new every day. Would have made my life easier if I had know about this 6 months ago when I needed to design something similar. Oh well. Maybe I'll get a chance to refactor my code at some point =D – Nevyn Jul 25 '12 at 19:50
  • Your edit makes sense, probably what OP is looking for. As such the concept of a "bidirectional keyed collection" doesn't make sense, because if you have the item, then you always have the key even without any collection. Keyed collection facilitates the other way need. – nawfal Mar 30 '13 at 08:06
1

The Dictionary....or IDictionary interface is the closest I can think of to what you want. It doesn't have quite so simple a searching operation, in that searching on a value can return the key, but I do know you can search on a key to get a value. providing functionality for the reverse in a custom extended class wouldn't be difficult at all.

MSDN IDictionary page

Nevyn
  • 2,623
  • 4
  • 18
  • 32
  • KeyedCollection is definitely the better way to go. It implements Dictionaries behind the scenes anyway =D – Nevyn Jul 25 '12 at 19:47
1

Could this method fit your needs?

public static class Extensions
{
    public static TKey GetKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, TValue value)
    {
        int index = dict.Values.ToList().IndexOf(value);

        if (index == -1)
        {
            return default(TKey); //or maybe throw an exception
        }

        return dict.Keys.ToList()[index];
    }
}

You could then use it like so:

Dictionary<int, char> dict = new Dictionary<int, char>();
dict.Add(1, 'a');
dict.Add(4, 'b');
dict.Add(6, 'c');
dict.Add(5, 'd');

Console.WriteLine(dict.GetKey('d')); //5
Daniel
  • 2,944
  • 3
  • 22
  • 40