Reputation: 3203
Is it possible to force a Dictionary to have unique values? See the following example.
Dictionary<string, string> types = new Dictionary<string, string>()
{
{"1", "one"},
{"2", "two"},
{"3", "three"}
};
In the event some one tried to execute the following line, they should receive an error.
types.Add("4","one");
I know this is not how a dictionary is built to operate and the correct answer may be to use a different/custom data structure.
Upvotes: 3
Views: 9618
Reputation: 73442
unfortunately Dictionary
provided by framework doesn't provide this feature.
Fastest workaround would be build something like this
public class UniqueValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public new void Add(TKey key, TValue value)
{
if (this.ContainsValue(value))
{
throw new ArgumentException("value already exist");
}
base.Add(key, value);
}
public new TValue this[TKey key]
{
get
{
return base[key];
}
set
{
if (this.ContainsValue(value))
{
throw new ArgumentException("value already exist");
}
base[key] = value;
}
}
}
Or something like the following(which is better in performance but not memory)
public class UniqueValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
Dictionary<TValue, TKey> valueAsKey = new Dictionary<TValue, TKey>();
public new void Add(TKey key, TValue value)
{
if (valueAsKey.ContainsKey(value))
{
throw new ArgumentException("value already exist");
}
base.Add(key, value);
valueAsKey.Add(value, key);
}
public new TValue this[TKey key]
{
get
{
return base[key];
}
set
{
if (valueAsKey.ContainsKey(value))
{
throw new ArgumentException("value already exist");
}
if (!this.ContainsKey(key))
{
this.Add(key, value);
}
else
{
base[key] = value;
valueAsKey[value] = key;
}
}
}
//You may need to handle remove as well
}
Note:this will work only when you use UniqueValueDictionary<TKey, TValue>
type, If you cast to Dictionary<TKey, TValue>
you can add duplicate values.
As pointed in comments you can build something like this inheriting from IDictionary<TKey, TValue>
not Dictionary<TKey, TValue>
taking this as an idea.
Upvotes: 3
Reputation: 23786
You probably want to implement IDictionary
and internally just call the corresponding Dictionary<TKey,TValue>
methods. Also, you want a HashSet<TValue>
. And then, on your Add method you would first check to see if your hashset.Contains(value)
. If it does, then you throw an exception.
On the other hand, do you really NEED this behavior? What if you just use a HashSet<Tuple<string,string>>
. Then, any duplicates are just ignored. Or do you really NEED the data structure to throw an exception? If you don't, that's what I would go with.
Edit: good point @Alexei Levenkov. If you will have the same value with different keys, then the HashSet approach doesn't give you what you originally asked for. That would only be applicable if you were expecting the SAME key/value pairs.
Upvotes: 6
Reputation: 203821
Keep two data structures; your regular dictionary and a HashSet<string>
for the values. When you would like to add an item first check if the value is in the hash set. If it's not, then you know it's safe to add to both the dictionary and the set. (Also ensure you remove items from both collections on removal.)
If this is done in enough places then it may be worth creating your own IDictionary<K,V>
implementation that uses both a regular Dictionary
and a HashSet
internally, so that you don't need to do so much work when using it. If this particular structure is only used in just a few places, it may not be worth the investment to create such a class.
Upvotes: 12
Reputation: 15112
Check for types.ContainsValue
before adding
string str = "one";
if (!types.ContainsValue(str)) //doesn't add if its already there
{
types.Add("4", str);
}
Upvotes: 4