3

Possible Duplicate:
C# dictionary type with unique keys and values

I would like to make sure that a dictionary has unique keys AND values. Is there any way to add this kind of validation outside of building my own class? That is the only way I can think of accomplishing validation for values in a dictionary. But, maybe there is some attribute I could add that I cannot seem to find via google.

I am looking to use this dictionary with WPF bindings, if that helps, also.

Community
  • 1
  • 1
Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • Don't think there's any attribute that would do something like that. It's up to the dictionary implementation. Best bet would be to wrap it with your own class (even though you don't want to do it) or write a Linq query or utility method to check an existing dictionary. – Chris Sinclair Sep 05 '12 at 17:56
  • 5
    Create two dictionaries `new Dictionary()` and `new Dictionary()` – L.B Sep 05 '12 at 17:56
  • You mean a unique value for a unique key.??? – perilbrain Sep 05 '12 at 17:57
  • Is data assumed to be constant, or what if a value in the dictionary changes, so it becomes equal to another value. Just by changing the instance of a value without the dictionary knowing... (I wonder how an ordinary dictionary handles the similar effect on key objects becoming equal.) – erikH Sep 05 '12 at 18:59
  • @L.B That would not work for my purpose (I have updated that I am going to use this in WPF data binding) – Justin Pihony Sep 06 '12 at 04:11
  • @Mike Yah, I had seen that and was mainly trying to avoid the wrapped class and seeing if there was something out of the box. But, it seems I will have to go down that road. – Justin Pihony Sep 06 '12 at 04:12
  • @erikH Yah, I need to deal with all of those conditions (add/insert/delete) – Justin Pihony Sep 06 '12 at 04:13
  • @erikH - Keys are not allowed to change once added to a dictionary. If they do the dictionary's behaviour becomes undefined. – Enigmativity Sep 06 '12 at 04:55
  • @erikH But, the values can, and that is what I need to monitor. Also, I meant to say (add/update/delete) – Justin Pihony Sep 06 '12 at 14:13

2 Answers2

5

Dictionary keys are unique, by definition. Ensuring dictionary values are unique is done the same way you'd check every array or collection member is unique.

.NET 3.5 introduces HashSet<T> which speeds things up, assuming your TValue type implements Equals(TValue).

HashSet<TValue> seenValues = new HashSet<TValue>();
foreach(TKey key in myDictionary) {
    if( seenValues .Contains( myDictionary[key] ) ) throw new Exception("Dictionary contains duplicate item.");
    seenValues .Add( myDictionary[key] );
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Or just `foreach(TValue value in myDictionary.Values)`. – erikH Sep 05 '12 at 22:14
  • Yes, you're right. Originally I thought that the `.Values` property was not guaranteed to return values in the same order as the `.Keys` property (such as automatically removing duplicate values), but the MSDN documentation says it does, soooo yeah. – Dai Sep 05 '12 at 23:43
  • As specified, I am looking for something that would not require writing my own class...out of the box...guess there isnt anything – Justin Pihony Sep 06 '12 at 04:14
  • But you don't need to write a new class with the example I gave. – Dai Sep 06 '12 at 13:28
0

You could try using this two-way dictionary class:

public class Map<T1, T2>
{
    private Dictionary<T1, T2> _forward = new Dictionary<T1, T2>();
    private Dictionary<T2, T1> _reverse = new Dictionary<T2, T1>();

    public Map()
    {
        this.Forward = new Indexer<T1, T2>(_forward);
        this.Reverse = new Indexer<T2, T1>(_reverse);
    }

    public class Indexer<T3, T4>
    {
        private Dictionary<T3, T4> _dictionary;
        public Indexer(Dictionary<T3, T4> dictionary)
        {
            _dictionary = dictionary;
        }
        public T4 this[T3 index]
        {
            get { return _dictionary[index]; }
            set { _dictionary[index] = value; }
        }
    }

    public void Add(T1 t1, T2 t2)
    {
        _forward.Add(t1, t2);
        _reverse.Add(t2, t1);
    }

    public Indexer<T1, T2> Forward { get; private set; }
    public Indexer<T2, T1> Reverse { get; private set; }
}

You can use it like this:

var map = new Map<int, string>();

map.Add(42, "Hello");

Console.WriteLine(map.Forward[42]);
// Outputs "Hello"

Console.WriteLine(map.Reverse["Hello"]);
//Outputs 42

It's a fairly simple implementation. You would probably need to expose some of the underlying dictionary functionality, but at least it is a start.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172