Searching a String in a Dictionary - c#

I have this Class Form1.cs where I created my GUI, It also has a combobox with following functionality:
string SelectedItemName = (string)comboBox2.SelectedItem.ToString();
Console.WriteLine(SelectedItemName);
if (comboBox2.SelectedIndex > -1)
{
testvariabel2.GetSessionName();
}
So I check if the user has chose something from the ComboBox and than I call the Function GetSessionName in my other Class CTestRack.cs.
Dictionary<string, Dictionary<string, string>> newDictionary = new Dictionary<string,Dictionary<string, string>>();
foreach (SectionData section in data.Sections)
{
var keyDictionary = new Dictionary<string, string>();
foreach (KeyData key in section.Keys)
keyDictionary.Add(key.KeyName.ToString(), key.Value.ToString());
newDictionary.Add(section.SectionName.ToString(), keyDictionary);
if (newDictionary.ContainsKey(testvariabel.SelectedItemName))
{
Console.WriteLine("Key: {0}, Value: {1}", keyDictionary[testvariabel.SelectedItemName]);
}
else Console.WriteLine("Couldn't check Selected Name");
}
Here I'd like to check if the String SelectedItemName exists in my Dictionary, but I always get the Systen.ArgumentNullException that the String SelectedItemName is NULL in my CTestRackClass.
Now my question, how do I search the dictionary in CTestRack for the String setted in the other Class
Form1 ?

Well... actually you got the looking into the dictionary right ! To find out if a key is present in a dictionary, you use ContainsKey.
if(myDictionary.ContainsKey(myKey))
{
//do something
}
However, your problems comes from the fact that null is never a valid key in a dictionary (mainly because null doesn't have a proper hash code). So you need to ensure that the key you're looking for is not null. From your code, I guess that testvariabel.SelectedItemName has not been set as it should.
Moreover there is a more efficient way to look if a value is present before doing something with it. Use TryGetValue:
TValue val;
if(myDictionary.TryGetValue(myKey, out val))
{
//do something with val
}
That way you don't need to access myDictionary[myKey]. If you use ContainsKey, you are in fact accessing the same value twice. That a small cost in most cases, but very easy to avoid, so you should give it a try.
Note that I answered only the specific question about looking into a dictionary. I cannot say anything about the correctness of your code as a whole.

I see there are two clear issues with your code.
You are checking if a key exists in one dictionary (newDictionary) but trying to retrieve it from another (keyDictionary )
You are try to look up keys in the dictionary even before it's completely built. Move the if check outside of foreach loop.

Related

How to check if a MultiValueDictionary contains a specific value

MultiValueDictionary is an experimental implementation of a multi-value dictionary in c#. It allows you to have multiple values per key. I need help creating code that works like,
(If MultiValueDictionary contains value "pudding", then do this). Here is a code example of what I need:
Class field declaration:
public MultiValueDictionary<string, string> _cookBook = new MultiValueDictionary<string, string>();
Then using in some method:
_cookBook.Add("food", "icing");
_cookBook.Add("food", "pudding");
_cookBook.Add("dessert", "pudding");
if(_cookBook.Contains("pudding"))
{
//Do this
}
MultiValueDictionary is available through NuGet as Microsoft.Experimental.Collections. Since this is a relatively new type of dictionary, I'm not finding a lot of information on it. Any help on how to accomplish this would be greatly appreciated.
I think you can do that as usual:
//If you know item key and value
if (_cookBook.Contains("food", "icing"))
{
//Do something
}
//If you know item key
if (_cookBook.ContainsKey("food"))
{
//Do something
}
//If you know item value
if (_cookBook.ContainsValue("icing"))
{
//Do something
}
Tested with Microsoft Experimental Collections 1.0.3-alpha

C# Copy one record from one dictionary to another

I need to copy one record from one dictionary to another, only one. I have tried the below, It doesn't copy one but everything due to that its in the loop. And I need to check if the key is not already copied over to the second dictionary that's why I looped over the first dictionary.
foreach (int key in firstDict.Keys)
{
if (!secondDict.ContainsKey(key))
secondDict.Add(key, firstDict[key]);
else {break;}
}
Please help, should you require more info please let me know.
Try this:
foreach (int key in firstDict.Keys)
{
if (!secondDict.ContainsKey(key))
{
secondDict.Add(key, firstDict[key]);
break;
}
}
A tiny bit more efficient than the others answers already posted (saves one dictionary lookup).
foreach(var kvp in firstDict)
{
if(!secondDict.ContainsKey(kvp.Key))
{
secondDict[kvp.Key] = kvp.Value;
break;
}
}
And if you're familiar with linq you may want to avoid the whole foreach ... break pattern. That pattern is pretty ugly and more importantly confusing: it looks like you want to copy everything when you really want to copy just one. Your question itself is proof of how confusing it is: if you don't get a pattern that should be simple right, that probably means the pattern is not very good. The following will do the work, and it's crystal clear it will only add ONE (at most) entry to the second dictionary.
var missingEntry = firstDict
// cast beacause KeyValuePair is a struct and I want to detect the case where there is no missing entry
.Cast<KeyValuePair<TKey,TValue>?>()
.FirstOrDefault(kvp => !secondDict.ContainsKey(kvp.Key));
// check whether there truely is a missing entry.
if (missingEntry != null)
{
secondDict[missingEntry.Key] = missingEntry.Value;
}
remove the else clause
foreach (int key in firstDict.Keys)
{
if (!secondDict.ContainsKey(key)) {
secondDict.Add(key, firstDict[key]);
break;
}
}
I suppose you have the key of that row in a certain variable that i will call key. here for example I'll set its value to 3.
int key = 3;
if (!secondDict.ContainsKey(key))
secondDict.Add(key, firstDict[key]);
EDIT:
If you want only any single entry that is not present in present in secondDict:
foreach (KeyValuePair<int, MyValueType> kvp in firstDict) //Replace MyValueType with the real value type in firstDict
{
if (!secondDict.ContainsKey(kvp.Key))
{
secondDict.Add(kvp.Key, kvp.Value);
break;
}
}

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();

Loop in Dictionary

I use this:
foreach(KeyValuePair<String,String> entry in MyDic)
{
// do something with entry.Value or entry.Key
}
The problem is that I can't change the value of entry.Value or entry.Key
My question is that how can i change the value or key when looping through a dictionary?
And, does dictionary allow duplicated key? And if yes, how can we avoid ?
Thank you
You cannot change the value of a dictionary entry while looping through the items in the dictionary, although you can modify a property on the value if it's an instance of a reference type.
For example,
public class MyClass
{
public int SomeNumber { get; set;}
}
foreach(KeyValuePair<string, MyClass> entry in myDict)
{
entry.Value.SomeNumber = 3; // is okay
myDict[entry.Key] = new MyClass(); // is not okay
}
Trying to modify a dictionary (or any collection) while looping through its elements will result in an InvalidOperationException saying the collection was modified.
To answer your specific questions,
My question is that how can i change the value or key when looping through a dictionary?
The approach to both will be pretty much the same. You can either loop over a copy of the dictionary as Anthony Pengram said in his answer, or you can loop once through all the items to figure out which ones you need to modify and then loop again through a list of those items:
List<string> keysToChange = new List<string>();
foreach(KeyValuePair<string, string> entry in myDict)
{
if(...) // some check to see if it's an item you want to act on
{
keysToChange.Add(entry.Key);
}
}
foreach(string key in keysToChange)
{
myDict[key] = "new value";
// or "rename" a key
myDict["new key"] = myDict[key];
myDict.Remove(key);
}
And, does dictionary allow duplicated key? And if yes, how can we avoid ?
A dictionary does not allow duplicate keys. If you want a collection of <string, string> pairs that does, check out NameValueCollection.
Updating the dictionary in the loop is going to be a problem, as you cannot modify the dictionary as it is being enumerated. However, you can work around this pretty easily by converting the dictionary to a list of KeyValuePair<> objects. You enumerate that list, and then you can modify the dictionary.
foreach (var pair in dictionary.ToList())
{
// to update the value
dictionary[pair.Key] = "Some New Value";
// or to change the key => remove it and add something new
dictionary.Remove(pair.Key);
dictionary.Add("Some New Key", pair.Value);
}
For the second part, the key in a dictionary must be unique.
KeyValuePair's Key and value are read only. But you can change a value like that:
dictionary[key].Value = newValue;
But if you want to change the key, you will have to remove/add a key.
And no, a Dictionary does not allow duplicate keys, it will throw an ArgumentException.
You cannot modify keys while enumerating them.
One method I use for changes to the collection while enumerating them is that I do break; out of the foreach loop when a match is found and item is modified, and am restarting the whole enumeration all over again. That's one way of handling it...
No, Dictionary can't have duplicate keys. If you want something that will sort by key and allow duplicates, you should use some other data structure.
You can do this like
for (int i = 0; i < MyDic.Count; i++)
{
KeyValuePair<string, string> s = MyDic.ElementAt(i);
MyDic.Remove(s.Key);
MyDic.Add(s.Key, "NewValue");
}
And Dictionary doesn't allow duplicates

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