5

Can I make sure that in dictionary in C# there will be only a single of a specific value in it?

For example, if I define a Dictionary which key is char and value is char, can I make sure that if the character 'a' is already an existing value, there won't be another value 'a' in the dictionary?

I have a solution, but I'd like to know if there's a better one:

static void Main()
{
    Dictionary<int, int> dic = new Dictionary<int, int>();
    bool valExists = false;
    Console.WriteLine("please enter key and value");
    int key = int.Parse(Console.ReadLine());
    int val = int.Parse(Console.ReadLine());
    foreach (KeyValuePair<int,int> keyval in dic)
    {
        if (keyval.Value == val)
        {
            valExists = true;
            break;
        }
    }
    if (!valExists)
        dic.Add(key, val);
}
Servy
  • 202,030
  • 26
  • 332
  • 449
  • Probably you should use that value as the Key? http://stackoverflow.com/questions/9438060/c-sharp-dictionary-type-with-unique-keys-and-values may help? – Siva Mar 03 '14 at 19:59

4 Answers4

5

Can I make sure that in dictionary in C# there will be only a single of a specific value in it?

Not as such (it wouldn't follow the the normal dictionary contract at that point), but it sounds like you effectively want a bi-directional dictionary. You can do that by composing two dictionaries, one going in each direction. I have an answer on another question with sample code for that.

That will allow you to go directly from "value" to "key" - if you have no need for that, you could always just keep a HashSet<TValue> as well as the normal TDictionary<TKey, TValue> and throw an exception if the caller tries to add a value which already exists.

Again, I would urge you not to do this by deriving from Dictionary<,> - instead just compose a Dictionary<,> and a HashSet<>. (I wouldn't even implement IDictionary<,>, as you have additional constraints which normal dictionaries don't include.)

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

To avoid needing to do a linear search through the entire dictionary for each Add you can keep a HashSet<TValue> as well as the dictionary. When you add a new value, you can first check the set. If it's there, it's in the dictionary. If you end up adding the item, add it to the set. When removing items from the dictionary you also need to remove them from the set.

Servy
  • 202,030
  • 26
  • 332
  • 449
2

There's a built in method on the dictionary class to check if values exist. Note that this is a linear search, so it's not the most efficient way, but it does exist...

static void Main()
{
    Dictionary<int, int> dic = new Dictionary<int, int>();

    Console.WriteLine("please enter key and value");
    int key = int.Parse(Console.ReadLine());
    int val = int.Parse(Console.ReadLine());

    if (!dic.ContainsValue(val))
        dic.Add(key, val);
}
Josh Anderson
  • 438
  • 3
  • 7
  • This is shorter than the OP's code, but it's still doing a linear search through the dictionary for every single `Add`. – Servy Mar 03 '14 at 20:07
  • @Servy Thanks, updated to reflect the method in which the `ContainsValue` search is done. OP already marked Jon's answer, so performance was probably the goal in mind rather than shortness. – Josh Anderson Mar 03 '14 at 20:26
0

This tells you if you have duplicate values or not:

dic.Values.Distinct().Count() == dic.Values.Count() // true if no duplicates found

To prevent duplicates:

if (!dic.ContainsValue(val)) {    
  dic[key] = val;
}

For better performance, use a seaparate HashSet.

var values = new HashSet<int>();

if (!values.Contains(val)) {
  values.Add(val);
  dic[key] = val;
}
  • 1
    The intent here is to see if a value exists before adding a new value *for every single `Add`*. Rather than to check after a bunch of duplicates are added. – Servy Mar 03 '14 at 20:00
  • You can use ContainsValue: if (!dic.ContainsValue(val)) { dic[key] = val; } –  Mar 03 '14 at 20:06
  • That makes the code shorter than what the OP is doing, but that's really all. You're still doing a linear search through the dictionary every single time. – Servy Mar 03 '14 at 20:06
  • In that scenario, I would store values in a separate HashSet or make the value actually a key. –  Mar 03 '14 at 20:08
  • Yes, that's what I said in my answer 10 minutes ago, and what Jon says in his. – Servy Mar 03 '14 at 20:10
  • I see. You did not specify what "better" means. Does better mean shorter? or higher performance? –  Mar 03 '14 at 20:13
  • It's not my question. – Servy Mar 03 '14 at 20:15