Difference between ContainsKey and ContainsValue in Dictionary? - c#

how does containsKey differ from containsValue ?
public Dictionary<string, string> dictionary = new Dictionary<string, string>();
if(dictionary.ContainsValue("123"))
{
}
if(dictionary.ContainsKey("123"))
{
}

Dictionarys are mappings from a key to a value.
ContainsKey() checks if your dictionary contains a certain key, it is very fast - looking up keys (and finding the data associated with that key) is the main strength of dictionaries. You might need this, to avoid accessing a non-existent Key - read about TryGetValue() in that case - it might be a better choice to avoid accessing non existing keys data.
ContainsValue() iterates over all values and checks if it is in the dictionary, it is a slow and cumbersome procedure because it needs to go to all values until the first one matches. Accessing values not by its key, but by iterating all is not what dictionaries are about.
Doing a ContainsKey() is fine, if you feel you need to do a ContainsValue() you are probably operating on the wrong kind of data structure.
Doku:
ContainsKey() vs. TryGetValue()
ContainsValue()

ContainsKey check given object (in this case string ) is exist in Keys. Dictionary use hash, so this operation is executed very fast ( O(1) complexity).
ContainsValue check given object (int this case int ) is exist in Values or not.
public Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("123", 321);
if(dictionary.ContainsValue(321)) // return true
{
}
if(dictionary.ContainsKey("123")) //return true
{
}

Related

Create a Dictionary with multiple keys and get value using one of keys

I want to create a Dictionary that have a multiple keys and when I want to get value using just one or more keys.
I tried :
Dictionary<Tuple<int, string>, string> dictionary = new Dictionary<Tuple<int, string>, string>();
var Key =new Tuple<int,string>(1,"I1");
var Value = "this is a value";
dictionary.Add(Key, Value);
When I try to get value from the dictionary I Must / Should enter all the keys
Like this :
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"I1")]}");
But when I try to get value using just one of keys like this
MessageBox.Show($"{dictionary[new Tuple<int, string>(1,"")]}");
I got error, I know that this error happened cause dictionary need the full exist key to return a value.
So please anyone have any Idea about how can I create a Dictionary with multiple keys and when retrieving value using just one or more or all keys ?
Dictionaries in .NET are expected to have close to O(1) lookup times. To achieve this, they make use of the GetHashCode() and Equals() methods of the key objects. The resulting hash code is used to divide the dictionary's contents into partitions. When you look up an item, the partition is identified using the hash code, all the items in that partition with a matching hash code* are compared to the key you're looking up using the Equals() method.
Here you are trying to create a dictionary with two keys for every object. You're doing this using a Tuple to make one key. The GetHashCode() result of a Tuple is based on both of its values, so the performance of a dictionary is lost if you want to look up values by only half of the key. You would need to go through the entire dictionary comparing each individual item, rendering it little better than a list.
One solution would be to make a dictionary that has a string->int key lookup, and then the other dictionary just be int->string. This would require two lookups when using string keys, but might be a good solution.
Example:
Dictionary<string, int> stringKeyToIntKey = new Dictionary<string, int>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
intKeyDict[1] = "Test";
stringKeyToIntKey["I1"] = 1;
Console.WriteLine(intKeyDict[1]);
Console.WriteLine(intKeyDict[stringKeyToIntKey["I1"]]);
An add method could look like this:
public void AddEntry(int intKey, string stringKey, string value)
{
intKeyDict[intKey] = value;
stringKeyToIntKey[stringKey] = intKey;
}
And you could wrap TryGetValue to make life easier:
public bool TryGetValue(string stringKey, out string value)
{
value = null;
return stringKeyToIntKey.TryGetValue(stringKey, out int intKey) && intKeyDict.TryGetValue(intKey, out value);
}
Delete would look like this:
public void DeleteEntry(string stringKey)
{
if (stringKeyToIntKey.TryGetValue(stringKey, out int intKey))
{
intKeyDict.Remove(intKey);
stringKeyToIntKey.Remove(stringKey);
}
}
You would have to make sure that items are added and removed from both dictionaries at the same time. When you add an item to intKey, you would need to add the corresponding key mapping to stringKeyToIntKey.
Alternatively, you could have two dictionaries: one with a string key and one with an int key, and each would have the same values. Again you would have to add and remove items at the same time, and you would also have to update the values in both at the same time.
Example:
Dictionary<string, string> stringKeyDict = new Dictionary<string, string>();
Dictionary<int, string> intKeyDict = new Dictionary<int, string>();
stringKeyDict["I1"] = "hello";
intKeyDict[1] = "hello";
Console.WriteLine(stringKeyDict["I1"]);
Console.WriteLine(intKeyDict[1]);
This is my favoured approach where the values are class instances, since both dictionaries will reference the same class instances for my items, and thus changes to properties of those instances will be reflected in both. For strings, however, the first option might be better.
* Hash codes are not unique and multiple objects can potentially have the same hash code, even if their values are not the same
You can use string for dictionary keys. Let's say you want to create a key from int x = 5 and string y = "str". You can concat and split them with some separator, and create a key like this:
string key = $"{x}:{y}"
And let's say you want to get elements only by x. you can write something like this:
dictionary.Where(kvp=>kvp.Key.Contains($"{x}:"))
of course, it will not give elements in O(1) time(it will give you elements in O(n) time) but it will work. If you want to get elements in O(1) time only by x I am not sure if it's possible with one dictionary.

How do I get the Index of a key in a dictionary? [duplicate]

I need to do currentKey+1. So i would like to find the index of the key value and get the next key (or first if at end). How do i find the current index of the key?
I am using a Dictionary<int, classname> and i looked for .Find or IndexOf with Linq to no avail.
Dictionaries are not sorted, so the Key doesn't have any index really. See my question here: Accessing a Dictionary.Keys Key through a numeric index
Use an OrderedDictionary which has an indexer that takes an Int.
Edit: 'm not really sure I understand what you want. If you want to iterate through a Dictionary, just use
foreach(KeyValuePair kvp in yourDict)
If the key is an Int and you want the next, use
var newkey = oldkey+1;
if(yourdict.ContainsKey(newkey)){
var newvalue = yourdict[newkey];
}
If the ints are not sequential, you can use
var upperBound = d.Max(kvp => kvp.Key)+1; // to prevent infinite loops
while(!yourdict.ContainsKey(newkey) && newkey < upperBound) {
newkey++;
}
or, alternatively:
var keys = (from key in yourdict.Keys orderby key select key).ToList();
// keys is now a list of all keys in ascending order
As Michael Stum noted, Dictionary<TKey, TValue> is not sorted (it's a hashtable) so there is no such thing as the "index" of a key. Instead, you can use SortedList which is (as the name implies) sorted and does provide an IndexOfKey method.
Be aware that the performance characteristics of Dictionary<TKey, TValue> is different to SortedList<TKey, TValue> though. While Dictionary is O(1) for inserts and deletes, SortedList is O(logn).
Without using a different collection it could be done like this. Though I'm not sure how efficient this is.
classIndex = classes.ToList().IndexOf(new KeyValuePair<int, classname>(newKey, classes[newKey]));

Creating dictionaries with pre-defined keys C#

I'm looking for a way to define a dictionary for reuse. ie. I can create the dictionary object without having to populate it with the values I want.
Here is what I have currently (note code not tested, just example)
public Dictionary<string, string> NewEntryDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
// populate key value pair
foreach(string name in Enum.GetNames(typeof(Suits))
{
dic.Add(name, "");
}
return dic;
}
The end result should be a new dictionary object with a predefined set of keys.
But I want to avoid doing it this way.
It's not really clear whether you're concerned about the amount of code you've written, or the efficiency of it. From an efficiency perspective, it's fine - it's O(N), but that's hard to avoid if you're populating a dictionary with N entries.
You can definitely make the source code shorter though, using LINQ:
public Dictionary<string, string> NewEntryDictionary()
{
return Enum.GetNames(typeof(Suits)).ToDictionary(name => name, name => "");
}
That won't be any more efficient, of course... it's just shorter code.
If you do ONLY want to save values according to your enum, use
Dictionary<Suits,String> instead of Dictionary<String,String>
Everything else, Jon already said. Use LinQ for a bit more "fancy" look. But that does not do better performance

Make an existing Dictionary case insensitive .Net

I know how to make a new dictionary case insensitive with the code below:
var caseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
But I'm using WebApi which serializes JSON objects into a class we've created.
public class Notification : Common
{
public Notification();
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings { get; set; }
}
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
Thanks
So besides rebuilding the dictionary after receiving the "Notification" object, is there a way to set this dictionary to case insensitive in the first place or after it's been created?
No, it is impossible. You need to create a new dictionary.
Currently the dictionary has all of the keys in various different buckets; changing the comparer would mean that a bunch of keys would all suddenly be in the wrong buckets. You'd need to go through each key and re-compute where it needs to go and move it, which is basically the same amount of work as creating a new dictionary would be.
Whenever an item is added to a dictionary, the dictionary will compute its hash code and make note of it. Whenever a dictionary is asked to look up an item, the dictionary will compute the hash code on the item being sought and assume that any item in the dictionary which had returned a different hash code cannot possibly match it, and thus need not be examined.
In order for a dictionary to regard "FOO", "foo", and "Foo" as equal, the hash code function it uses must yield the same value for all of them. If a dictionary was built using a hash function which returns different values for "FOO", "foo", and "Foo", changing to a hash function which yielded the same value for all three strings would require that the dictionary re-evaluate the hash value of every item contained therein. Doing this would require almost as much work as building a new dictionary from scratch, and for that reason .NET does not support any means of changing the hash function associated with a dictionary other than copying all the items from the old dictionary to a new dictionary, abandoning the old one.
Note that one could design a SwitchablyCaseSensitiveComparator whose GetHashCode() method would always return a case-insensitive hash value, but whose Equals method could be switched between case-sensitive and non-case sensitive operation. If one were to implement such a thing, one could add items to a dictionary and then switch between case-sensitive and non-case-sensitive modes. The biggest problem with doing that would be that adding if the dictionary is in case-sensitive mode when two items are added which differ only in case, attempts to retrieve either of those items when the dictionary is in case-insensitive mode might not behave as expected. If populating a dictionary in case-insensitive mode and performing some look-ups in case-sensitive mode should be relatively safe, however.
Try changing your class definition to something like this
public class Notification : Common
{
public Notification()
{
this.substitutionStringsBackingStore =
new Dictionary<string,string>( StringComparer.OrdinalIgnoreCase )
;
}
[JsonProperty("substitutionStrings")]
public Dictionary<string, string> SubstitutionStrings
{
get { return substitutionStringsBackingStore ; }
set { substitutionStringsBackingStore = value ; }
}
private Dictionary<string,string> substitutionStringsBackingStore ;
}
You do have to re-create the dictionary, but this can be done with extensions:
public static class extensions
{
public static Dictionary<string, T> MakeCI<T>(this Dictionary<string, T> dictionary)
{
return dictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
}
}
I've specified string type for the key as this is what we want to be CI, but the value can be any type.
You would use it like so:
myDict = myDict.MakeCI();

Get index of a key/value pair in a C# dictionary based on the value

I would like to know if some property or method exists that gets the index of a specific value.
I found that dictionaries have the Contains() method which returns true if the value passed in exists, so this method almost implements what I need.
I know that I can loop through all the value pairs and check the condition, but I ask because maybe there's an optimized way of doing this.
Let's say you have a Dictionary called fooDictionary
fooDictionary.Values.ToList().IndexOf(someValue);
Values.ToList()
converts your dictionary values into a List of someValue objects.
IndexOf(someValue)
searches your new List looking for the someValue object in question
and returns the Index which would match the index of the Key/Value pair in the dictionary.
This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.
This does not however account for the issue that there may be several matching "someValue" objects.
There's no such concept of an "index" within a dictionary - it's fundamentally unordered. Of course when you iterate over it you'll get the items in some order, but that order isn't guaranteed and can change over time (particularly if you add or remove entries).
Obviously you can get the key from a KeyValuePair just by using the Key property, so that will let you use the indexer of the dictionary:
var pair = ...;
var value = dictionary[pair.Key];
Assert.AreEqual(value, pair.Value);
You haven't really said what you're trying to do. If you're trying to find some key which corresponds to a particular value, you could use:
var key = dictionary.Where(pair => pair.Value == desiredValue)
.Select(pair => pair.Key)
.FirstOrDefault();
key will be null if the entry doesn't exist.
This is assuming that the key type is a reference type... if it's a value type you'll need to do things slightly differently.
Of course, if you really want to look up values by key, you should consider using another dictionary which maps the other way round in addition to your existing dictionary.
Consider using System.Collections.Specialized.OrderedDictionary, though it is not generic, or implement your own (example).
OrderedDictionary does not support IndexOf, but it's easy to implement:
public static class OrderedDictionaryExtensions
{
public static int IndexOf(this OrderedDictionary dictionary, object value)
{
for(int i = 0; i < dictionary.Count; ++i)
{
if(dictionary[i] == value) return i;
}
return -1;
}
}
You can find index by key/values in dictionary
Dictionary<string, string> myDictionary = new Dictionary<string, string>();
myDictionary.Add("a", "x");
myDictionary.Add("b", "y");
int i = Array.IndexOf(myDictionary.Keys.ToArray(), "a");
int j = Array.IndexOf(myDictionary.Values.ToArray(), "y");
You can use LINQ to help you with this.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "hi");
dict.Add(2, "NotHi");
dict.Add(3, "Bah");
var item = (from d in dict
where d.Value == "hi"
select d.Key).FirstOrDefault();
Console.WriteLine(item); //Prints 1
If searching for a value, you will have to loop through all the data. But to minimize code involved, you can use LINQ.
Example:
Given Dictionary defined as following:
Dictionary<Int32, String> dict;
You can use following code :
// Search for all keys with given value
Int32[] keys = dict.Where(kvp => kvp.Value.Equals("SomeValue")).Select(kvp => kvp.Key).ToArray();
// Search for first key with given value
Int32 key = dict.First(kvp => kvp.Value.Equals("SomeValue")).Key;
In your comment to max's answer, you say that what you really wanted to get is the key in, and not the index of, the KeyValuePair that contains a certain value. You could edit your question to make it more clear.
It is worth pointing out (EricM has touched upon this in his answer) that a value might appear more than once in the dictionary, in which case one would have to think which key he would like to get: e.g. the first that comes up, the last, all of them?
If you are sure that each key has a unique value, you could have another dictionary, with the values from the first acting as keys and the previous keys acting as values. Otherwise, this second dictionary idea (suggested by Jon Skeet) will not work, as you would again have to think which of all the possible keys to use as value in the new dictionary.
If you were asking about the index, though, EricM's answer would be OK. Then you could get the KeyValuePair in question by using:
yourDictionary.ElementAt(theIndexYouFound);
provided that you do not add/remove things in yourDictionary.
PS: I know it's been almost 7 years now, but what the heck. I thought it best to formulate my answer as addressing the OP, but of course by now one can say it is an answer for just about anyone else but the OP. Fully aware of that, thank you.
no , there is nothing similar IndexOf for Dictionary although you can make use of ContainsKey method to get whether a key belongs to dictionary or not

Categories