I have a nested Hashtable that looks like this.
Hashtable table = new Hashtable();
Hashtable subtable = new Hashtable();
Hashtable options = new Hashtable();
options.Add("file","foo");
subtable.Add("post_option",options);
table.Add(0,subtable);
//foreach here
This is what I have to work with, and I can't get any father up the chain to change what it is. So what I need to be able to do is get "foo" by calling for the key "file" starting from the "table" hashtable. I have tried every combo of foreach and .Keys and .Values. I just can't seem to get it lol. Thank you
Enumerator of Hashtable works similar to enumerator of IDictionary<TKey,TValue>, but it is not generic as it is ancient API came from .NET 1 where generics do not exist. So if you want to iterate over Hashtable with foreach you need to specify the type of item. In case of Hashtable it is DictionaryEntry.
foreach(DictionaryEntry tableEntry in table)
{
// your logic
}
If you do not know the keys of the first two tables, then you need to do something like this.
foreach(DictionaryEntry tableEntry in table)
{
Hashtable subtable = tableEntry.Value as Hashtable;
if (subtable == null)
continue;
foreach(DictionaryEntry subtableEntry in subtable)
{
Hashtable options = subtableEntry.Value as Hashtable;
if (options == null)
continue;
object file = options["file"];
}
}
You just need to do:
object foo = table[0]["post_option"]["file"];
Related
I have a dictionary which is dynamically generated. In the dictionary, for a single Key, there are multiple values. I am trying to access one of the values in those multiple values. My code so far:
var result = new Dictionary<string, object>();
var dictionary = deserialisedResult as IDictionary<string, object>;
foreach (var item in dictionary)
{
result.Add(item.Key, item.Value);
}
object o = result;
string[] names = o.GetType().GetProperties().Select(p => p.Name).ToArray();
foreach (var prop in names)
{
object propValue = o.GetType().GetProperty(prop).GetValue(o, null);
var value = propValue.GetValue(o,null);
}
But this is not working.
I need to get the values for 'resource'.
When I add watch, I see it nested as such:
Following line is causing issue out here:
string[] names = o.GetType().GetProperties().Select(p => p.Name).ToArray();
GetType() for Object base class type will not yield a Type, which can provide the PropertyInfo[], that you are looking for, even otherwise you are trying to run it for Dictionary<string,object> type, which anyway doesn't have properties to help find the relevant information. For it the Type would always be Dictionary
What you need is fetch the key collection from Dictionary and use them to fetch the values stored in the Dictionary
foreach (var key in result.Keys)
{
var value = result[key];
}
Solution is based on code provided in the question, I am not sure if you have further requirements
I have an advanced program that retrieves data from a database and creates objects from the data via ExpandoObjects in C#.
I'm now in the process of optimizing my entire process but came upon a piece of code that was the bottleneck performance-wise. I am quite curious how far I can furhter optimize this piece of code and already managed to run it 3 times as fast by doing the following:
Seperated 'the finding 'types' section' in a seperate for loop and only iterate over it when it hasn't been initialized yet.
Added a case for when the value is null and create an empty string instead, since for some reason Dictionary.Add slows down quite a lot when adding Null values.
// Holds all objects that are created inside the object.
Dictionary<string, IDictionary<string, dynamic>> objects = new Dictionary<string, IDictionary<string, dynamic>>();
// This foreach loop is the slowest part!
foreach (KeyValuePair<string, dynamic> pair in fields)
{
string type = pair.Key.Split('_')[0];
IDictionary<string, dynamic> obj;
if (!objects.TryGetValue(type, out obj))
{
obj = new ExpandoObject();
objects.Add(type, obj);
}
int location = pair.Key.IndexOf(type + "_");
string key = pair.Key.Remove(location, type.Length + 1);
if (pair.Value == null) // If Value is null, replace it with an empty string (dictionary slows quite alot when passing it null values)
obj.Add(key, "");
else
obj.Add(key, pair.Value);
}
if (types == null)
types = objects.Select(x => x.Key).ToList();
I am wondering, how is it that dictionary slows down that much when adding Null values, is it that in the underlying structure it does special operations when encountering null values? And is there something I'm missing to further optimize the code?.
Any help is again greatly appreciated.
UPDATE
Edited the code with the most recent changes I've gathered from SO.
You can avoid the multiple lookups in the dictionary by using TryGetValue instead of ContainsKey:
foreach (KeyValuePair<string, dynamic> pair in fields)
{
string type = pair.Key.Split('_')[0];
IDictionary<string, dynamic> obj;
if (!objects.TryGetValue(type, out obj))
{
obj = new ExpandoObject();
objects.Add(type, obj);
}
int location = pair.Key.IndexOf(type + "_");
string key = pair.Key.Remove(location, type.Length + 1);
if (pair.Value == null)
obj.Add(key, "");
else
obj.Add(key, pair.Value);
}
BTW: I don't see you using types in that second foreach loop. Therefore you can replace the first foreach loop with this simple code:
types = objects.Select(x => x.Key).ToList();
This should save quite a lot of time as it removes the slow search in the types list and the double parsing of the types.
Obviously this needs to be put after the foreach loop I showed above.
I have a NameValueCollection object and I need to convert it to a Hashtable object, preferrably in one line of code. How can I achieve this?
You should consider using a generic Dictionary instead since it's strongly-typed, whereas a Hashtable isn't. Try this:
NameValueCollection col = new NameValueCollection();
col.Add("red", "rouge");
col.Add("green", "verde");
col.Add("blue", "azul");
var dict = col.AllKeys
.ToDictionary(k => k, k => col[k]);
EDIT: Based on your comment, to get a HashTable you could still use the above approach and add one more line. You could always make this work in one line but 2 lines are more readable.
Hashtable hashTable = new Hashtable(dict);
Alternately, the pre-.NET 3.5 approach using a loop would be:
Hashtable hashTable = new Hashtable();
foreach (string key in col)
{
hashTable.Add(key, col[key]);
}
It takes more than one line but it's decently simple
NameValueCollection nv = new NameValueCollection();
Hashtable hashTable = new Hashtable();
nv.Add("test", "test");
foreach (string key in nv.Keys)
{
hashTable.Add(key, nv[key]);
}
It compiles and executes as expected.
I have an array of type Guid inside an HashTable
I get the values like the following but I can't get the array inside
IDictionaryEnumerator enumObj = moreTable.GetEnumerator();
while (enumObj.MoveNext())
{
foreach (var obj in enumObj.Value)
{
_guidList.Add(new Guid(obj.ToString()));
}
}
but this doesn't working with me any one know how to extract an array stored inside Hash table
You should use a type safe Dictionary and a generic List of Guid's instead:
Dictionary<Int32, Guid> guids = new Dictionary<Int32, Guid>();
guids.Add(1, new Guid("{25892e17-80f6-415f-9c65-7395632f0223}"));
guids.Add(2, new Guid("{e33898de-6302-4756-8f0c-5f6c5218e02e}"));
guids.Add(3, new Guid("{3a768eea-cbda-4926-a82d-831cb89092aa}"));
guids.Add(4, new Guid("{cd171f7c-560d-4a62-8d65-16b87419a58c}"));
guids.Add(5, new Guid("{17084b40-08f5-4bcd-a739-c0d08c176bad}"));
List<Guid> allGuids = new List<Guid>(guids.Values);
Assuming that your key is an integer, but that doesn't matter for the answer.
If you insist upon using a HashTable instead:
Hashtable guids = new Hashtable();
//fill Hashtable like above
ArrayList allGuids = new ArrayList(guids.Values);
foreach (Guid guid in allGuids) {
//do something with the GUID...'
}
[ all converted from VB.Net ]
I guess you should cast enumObj.Value to array, that should allow you to use it.
I'm trying to update a hashtable in a loop but getting an error: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
private Hashtable htSettings_m = new Hashtable();
htSettings_m.Add("SizeWidth", "728");
htSettings_m.Add("SizeHeight", "450");
string sKey = "";
string sValue = "";
foreach (DictionaryEntry deEntry in htSettings_m)
{
// Get value from Registry and assign to sValue.
// ...
// Change value in hashtable.
sKey = deEntry.Key.ToString();
htSettings_m[sKey] = sValue;
}
Is there way around it or maybe there is a better data structure for such purpose?
you could read the collection of keys into another IEnumerable instance first, then foreach over that list
System.Collections.Hashtable ht = new System.Collections.Hashtable();
ht.Add("test1", "test2");
ht.Add("test3", "test4");
List<string> keys = new List<string>();
foreach (System.Collections.DictionaryEntry de in ht)
keys.Add(de.Key.ToString());
foreach(string key in keys)
{
ht[key] = DateTime.Now;
Console.WriteLine(ht[key]);
}
In concept I would do:
Hashtable table = new Hashtable(); // ps, I would prefer the generic dictionary..
Hashtable updates = new Hashtable();
foreach (DictionaryEntry entry in table)
{
// logic if something needs to change or nog
if (needsUpdate)
{
updates.Add(key, newValue);
}
}
// now do the actual update
foreach (DictionaryEntry upd in updates)
{
table[upd.Key] = upd.Value;
}
If you're using a Dictionary instead of a Hashtable, so that the type of the keys is known, the easiest way to make a copy of the Keys collection to avoid this exception is:
foreach (string key in new List<string>(dictionary.Keys))
Why are you getting an exception telling you that you've modified the collection you're iterating over, when in fact you haven't?
Internally, the Hashtable class has a version field. The Add, Insert, and Remove methods increment this version. When you create an enumerator on any of the collections that the Hashtable exposes, the enumerator object includes the current version of the Hashtable. The enumerator's MoveNext method checks the enumerator's version against the Hashtable's, and if they're not equal, it throws the InvalidOperationException you're seeing.
This is a very simple mechanism for determining whether or not the Hashtable has been modified. In fact it's a little too simple. The Keys collection really ought to maintain its own version, and its GetEnumerator method ought to save the collection's version in the enumerator, not the Hashtable's version.
There's another, subtler design defect in this approach. The version is an Int32. The UpdateVersion method does no bounds checking. It's therefore possible, if you make exactly the right number of modifications to the Hashtable (2 times Int32.MaxValue, give or take), for the version on the Hashtable and the enumerator to be the same even though you've radically changed the Hashtable since creating the enumerator. So the MoveNext method won't throw the exception even though it should, and you'll get unexpected results.
The simplest way is to copy the keys into a separate collection, then iterate through that instead.
Are you using .NET 3.5? If so, LINQ makes things a little bit easier.
The key part is the ToArray() method
var dictionary = new Dictionary<string, string>();
foreach(var key in dictionary.Keys.ToArray())
{
dictionary[key] = "new value";
}
You cannot change the set of items stored in a collection while you are enumerating over it, since that makes life very difficult for the iterator in most cases. Consider the case where the collection represents a balanced tree, and may well undergo rotations after an insert. The enumerate would have no plausible way of keeping track of what it has seen.
However, if you are just trying to update the value then you can write:
deEntry.Value = sValue
Updating the value here has no impact on the enumerator.
This is how I did it within a dictionary; resets every value in dict to false:
Dictionary<string,bool> dict = new Dictionary<string,bool>();
for (int i = 0; i < dict.Count; i++)
{
string key = dict.ElementAt(i).Key;
dict[key] = false;
}
It depends on why you are looping through the items in the hashtable. But you would probably be able to iterate throught the keys instead. So
foreach (String sKey in htSettings_m.Keys)
{ // Get value from Registry and assign to sValue.
// ...
// Change value in hashtable.
htSettings_m[sKey] = sValue;
}
The other option is to create a new HashTable. Iterate through the first while adding items to the second then replace the original with the new one.
Looping through the keys requires less object allocations though.
List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
foreach (string key in keyList) {
It is the same as the other answers, but I like the one line to get the keys.
Convert it to an array:
private Hashtable htSettings_m = new Hashtable();
htSettings_m.Add("SizeWidth", "728");
htSettings_m.Add("SizeHeight", "450");
string sKey = "";
string sValue = "";
ArrayList htSettings_ary = new ArrayList(htSettings_m.Keys)
foreach (DictionaryEntry deEntry in htSettings_ary)
{
// Get value from Registry and assign to sValue.
// ...
// Change value in hashtable.
sKey = deEntry.Key.ToString();
htSettings_m[sKey] = sValue;
}
private Hashtable htSettings_m = new Hashtable();
htSettings_m.Add("SizeWidth", "728");
htSettings_m.Add("SizeHeight", "450");
string sValue = "";
foreach (string sKey in htSettings_m.Keys)
{
// Get value from Registry and assign to sValue
// ...
// Change value in hashtable.
htSettings_m[sKey] = sValue;
}
Maybe you can use Hashtable.Keys collection? Enumerating through that might be possible while changing the Hashtable. But it's only a guess...