2

Is there a built-in data structure for a key-key pair? I'm building a cross-reference table where each "side" of the reference is unique and corresponds to exactly one value on the other side.

For example, if I have a set of color names and color codes, I'd like to be to lookup a color by either its code or its name. A name lookup would return the color code while a code lookup would return the color name.

poke
  • 2,934
  • 5
  • 27
  • 37

2 Answers2

4

I think Jon Skeet's BiDictionary class is what you are looking for. Use it like:

BiDictionary<string, string> colors = new BiDictionary<string, string>();
colors.Add("Green", "00FF00");
colors.Add("Red", "FF0000");
colors.Add("White", "FFFFFF");
string code = colors.GetByFirst("Red");
string name = colors.GetBySecond("FF0000");
Console.WriteLine(code);
Console.WriteLine(name);

This is the class. I added GetByFirst and GetBySecond so that you can access it more like Dictionary's indexer instead of like its TryGetValue

using System;
using System.Collections.Generic;

class BiDictionary<TFirst, TSecond>
{
    IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
    IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

    public void Add(TFirst first, TSecond second)
    {
        if (firstToSecond.ContainsKey(first) ||
            secondToFirst.ContainsKey(second))
        {
            throw new ArgumentException("Duplicate first or second");
        }
        firstToSecond.Add(first, second);
        secondToFirst.Add(second, first);
    }

    public bool TryGetByFirst(TFirst first, out TSecond second)
    {
        return firstToSecond.TryGetValue(first, out second);
    }

    public TSecond GetByFirst(TFirst first)
    {
        return firstToSecond[first];
    }

    public bool TryGetBySecond(TSecond second, out TFirst first)
    {
        return secondToFirst.TryGetValue(second, out first);
    }

    public TFirst GetBySecond(TSecond second)
    {
        return secondToFirst[second];
    }
}
Community
  • 1
  • 1
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • 1
    @CoryNelson oops, you're right. Changed to Skeet's one-to-one dictionary. And I added an example of how it might be used in this question's context to help make this more than what should be a comment. – Tim S. Sep 17 '13 at 16:45
  • @huMptyduMpty added some methods and example to help this be a fuller answer. – Tim S. Sep 17 '13 at 16:51
0

This might not be an efficient way, but this might help,

public class MyDictinary<TKey, TVal> : Dictionary<TKey, TVal>
    {
        private Dictionary<TKey, TVal> _dictionary;
        public new int Count { get { return _dictionary.Count; } }
        public MyDictinary()
        {
            _dictionary = new Dictionary<TKey, TVal>();
        }

        public new void Add(TKey key, TVal val)
        {
            if (UniqueValueCheck(val))
            {
                _dictionary.Add(key, val);
            }
        }

        private bool UniqueValueCheck(TVal val)
        {
            return _dictionary.Aggregate(true, (current, pair) => current && !pair.Value.Equals(val));
        }
    }

Extend Dictionary and override(hide in this case) the add method and while adding just check for unique value.

Hossain Muctadir
  • 3,546
  • 1
  • 19
  • 33