C# Dictionary Clear() clears dictionary in dictionary - c#

So I got C# foreach loop which goes like this
foreach(Type s in source)
{
dic1.Clear();
dic1.Add(Key1, s.Attr1);
dic1.Add(Key2, s.Attr2);
...
dic1.Add(KeyN, s.AttrN);
dic2.Add(ind, dic1);
ind++;
}
It gets the values and sets them correctly, no problem in that.
But when the dic1.Clear() is called it clears the dic1 which was added in the dic2
and rewrites the contents of it with the new data being handled resulting N amount of dictionaries with the same data from the last handled data/object. Does the dic1.Clear() really affect the one which was added into the dic2? If it does should I just copy dic1 into dicTemp and add that one into dic2?
Thank you for advance.

I think I get your question now.
When you add a reference object to a collection you are storing a reference to the object, not the value.
What you should do is make dic1 local to the loop body.
foreach(Type s in source)
{
var dic1 = new Dictionary<T1, T2>();
dic1.Add(Key1, s.Attr1);
dic1.Add(Key2, s.Attr2);
...
dic1.Add(KeyN, s.AttrN);
dic2.Add(ind, dic1);
ind++;
}

Since you operate on only one instace through dic1 this will lead to:
All values in dic2 referring to the same dictionary instance
that instance being cleared in the beginning of each iteration.
You probably want to change the line dic1.Clear() to dic1 = new Dictionary<X, Y>().

Related

How to copy the content of a dictionary to another to clear the original one afterward

I want to copy the content of a dictionary to another named tempDict, so that i can still use the data of the original dictionary, even with clearing the first dictionary, the original one. Both dictionary have the same type
I've tried the following
Dictionary<string, Dictionary<int, List<dynamic>>> tempDict = new Dictionary<string, Dictionary<int, List<dynamic>>>(originalDict);
originalDict.Clear();
Dictionary<string, Dictionary<int, List<dynamic>>> tempDict = new Dictionary<string, Dictionary<int, List<dynamic>>>();
tempDict = originalDict;
originalDict.Clear();
But it doesn't seems to work, but to me, both method create a new instance of a dictionary, and then assign the instance value to originalDict, since it's a new instance, even by deleting the originalDict, how could both be deleted ? i don't really understand this one, i'm probably wrong, but if anyone could explain, would be great.
Thanks in advance !
My test code shows that the shallow copy of origDict to tempDict works fine:
Console.WriteLine(origDict.Count); // outputs 1
var tempDict = new Dictionary<string, Dictionary<int, List<dynamic>>>(origDict);
Console.WriteLine(tempDict.Count); // outputs 1
origDict.Clear();
Console.WriteLine(origDict.Count); // outputs 0
Console.WriteLine(tempDict.Count); // outputs 1

C# Iterating over a dictionary passed as a generic

I am having trouble trying to iterate over a dictionary passed to a function as a generic. For example, I have a function that loads data from a DB.
public T Load<T>(...)
This function can be called like so, with which I have no problems;
someclasstype data = Load<someclasstype>(...);
List<someclasstype> data = Load<List<someclasstype>>(...);
I've recently tried to extend this to be able to deal with dictionaries as well, and calling it like so:
Dictionary<long, someclasstype> data = Load<Dictionary<long, someclasstype>>(...)
I can load the data without a problem and store it in the dictionary no problem.
At this stage, the dictionary, with all its keyvaluepairs is stored in a variable called result, and I'm creating an IEnumerable with
IEnumerator resultIdx = ((IEnumerable)result).GetEnumerator();
if (!resultIdx.MoveNext())
return (T)result;
object kvp = resultIdx.Current;
So far so good. I can see the value of the key and the value of the value in a watch, or by mouseover on the kvp variable.
But I cannot figure out how to get the value part of the keyvaluepair from kvp.
// None of these work - I get compile time errors, unboxing errors, or invalid cast errors.
object item = ((KeyValuePair<TKey, TValue>)kvp).Value;
object item = ((KeyValuePair<long, object>)kvp).Value;
object item = ((T)kvp).Value // Never had a hope for this, but desperation...
Does anyone have any idea how I can do this?
try adding dynamic kvp = resultIdx.Current; . Then you can use kvp.Value
You can rewrite the function into two functions like.
public T Load<T>(...)
//Or maybe public List<T> Load<T>(...)
and
public Dictionary<long, T> LoadD<T>(...)
Then you can cast result to KeyValuePair<long, T> in LoadD. You can call Load from LoadD to minimize code rewriting.
Answer provided by Dede in comments:
"Use Reflection ?
object key kvp.GetType().GetProperty("Key").GetValue(kvp);
object value kvp.GetType().GetProperty("Value").GetValue(kvp);
Not very optimized, but can work... – Dede 24"

Using the Concurrent Dictionary - Thread Safe Collection Modification

Recently I was running into the following exception when using a generic dictionary
An InvalidOperationException has occurred. A collection was modified
I realized that this error was primarily because of thread safety issues on the static dictionary I was using.
A little background: I currently have an application which has 3 different methods that are related to this issue.
Method A iterates through the dictionary using foreach and returns a value.
Method B adds data to the dictionary.
Method C changes the value of the key in the dictionary.
Sometimes while iterating through the dictionary, data is also being added, which is the cause of this issue. I keep getting this exception in the foreach part of my code where I iterate over the contents of the dictionary. In order to resolve this issue, I replaced the generic dictionary with the ConcurrentDictionary and here are the details of what I did.
Aim : My main objective is to completely remove the exception
For method B (which adds a new key to the dictionary) I replaced .Add with TryAdd
For method C (which updates the value of the dictionary) I did not make any changes. A rough sketch of the code is as follows :
static public int ChangeContent(int para)
{
foreach (KeyValuePair<string, CustObject> pair in static_container)
{
if (pair.Value.propA != para ) //Pending cancel
{
pair.Value.data_id = prim_id; //I am updating the content
return 0;
}
}
return -2;
}
For method A - I am simply iterating over the dictionary and this is where the running code stops (in debug mode) and Visual Studio informs me that this is where the error occured.The code I am using is similar to the following
static public CustObject RetrieveOrderDetails(int para)
{
foreach (KeyValuePair<string, CustObject> pair in static_container)
{
if (pair.Value.cust_id.Equals(symbol))
{
if (pair.Value.OrderStatus != para)
{
return pair.Value; //Found
}
}
}
return null; //Not found
}
Are these changes going to resolve the exception that I am getting.
Edit:
It states on this page that the method GetEnumerator allows you to traverse through the elements in parallel with writes (although it may be outdated). Isnt that the same as using foreach ?
For modification of elements, one option is to manually iterate the dictionary using a for loop, e.g.:
Dictionary<string, string> test = new Dictionary<string, string>();
int dictionaryLength = test.Count();
for (int i = 0; i < dictionaryLength; i++)
{
test[test.ElementAt(i).Key] = "Some new content";
}
Be weary though, that if you're also adding to the Dictionary, you must increment dictionaryLength (or decrement it if you move elements) appropriately.
Depending on what exactly you're doing, and if order matters, you may wish to use a SortedDictionary instead.
You could extend this by updating dictionaryLength explicitly by recalling test.Count() at each iteration, and also use an additional list containing a list of keys you've already modified and so on and so forth if there's a danger of missing any, it really depends what you're doing as much as anything and what your needs are.
You can further get a list of keys using test.Keys.ToList(), that option would work as follows:
Dictionary<string, string> test = new Dictionary<string, string>();
List<string> keys = test.Keys.ToList();
foreach (string key in keys)
{
test[key] = "Some new content";
}
IEnumerable<string> newKeys = test.Keys.ToList().Except(keys);
if(newKeys.Count() > 0)
// Do it again or whatever.
Note that I've also shown an example of how to find out whether any new keys were added between you getting the initial list of keys, and completing iteration such that you could then loop round and handle the new keys.
Hopefully one of these options will suit (or you may even want to mix and match- for loop on the keys for example updating that as you go instead of the length) - as I say, it's as much about what precisely you're trying to do as much as anything.
Before doing foreach() try out copying container to a new instance
var unboundContainer = static_container.ToList();
foreach (KeyValuePair<string, CustObject> pair in unboundContainer)
Also I think updating Value property is not right from thread safety perspectives, refactor your code to use TryUpdate() instead.

Instancing with a dictionary

I am currently working on a project which creates a dictionary with an int index of the instance and a complex type as the value. Since this is a huge school project I do not want to post a ton of code as I have a logic problem rather than a "I need code". I'll try to be as clear as I can and if there is something I need to explain better please let me know.
First off. I have a dictionary in my server:
private Dictionary<int,List<complexType>> dictName = new Dictionary<int,List<complexType>>
Every time a client starts up it registers with the dictionary (i create a blank complex type to instantiate it then i load the dictionary):
List<complexType> temp = null;
dictName.Add(id,temp)
Then when the time comes that I want to add to the list for a particular instance I do this:
complexType myItem = new complexType();
dictName[id].Add(myItem);
When I run this code I get an error when a second client tries to run:
"An unhandled exception of type
'System.Reflection.TargetInvocationException' occurred in
mscorlib.dll. Additional information: Exception has been thrown by the
target of an invocation.
Now this happens when the second user hits:
dictName.Add(id,temp) from the first part.
If i change the instantiation of temp to List<complexType> temp = new List<complexType>();
then it passes that spot but I get the same error again when it updates the clients.
I am currently using this way of passing data with int and string (dictionary)
and they work fine but when I added in a List of a complex type in the dictionary I got the above error.
If anyone has any suggestions I would greatly appreciate it. I'm hoping it has something to do with my initial load of a blank list. If there is anything else you need to know please Ask Thanks!
You are making a dictionary of lists. So you were trying to add to a list that was null and that is what gave you the first exception.
Second, I've never seen the "new private Dictionary" is this a cut and paste typo?
This works:
Dictionary<int, List<string>> dictName = new Dictionary<int, List<string>>();
dictName.Add(0, new List<string>());
dictName[0].Add("First");
dictName.Add(1, new List<string>());
dictName[1].Add("Second");
The fact that you have list of a complex type and I have list of strings shouldn't matter.
Looks like you should initialize the dictionary entry as:
dictName.Add(id, new List<complexType>());
You can also try using the generic Lookup type, which is basically exactly what you need - key to a list of values.
var lookupName = new Lookup<int, complexType>();
lookup.Add(id, new complexType()); // Creates key 'id' and adds new ct.
lookup.Add(id, new complexType()); // Adds new ct to existing key 'id'
lookup.Add(651, null); // Creates key 651 and adds null
So you can just use the add method to add complex type instances to an id key without even thinking of whether the key exists or not.
lookup[id]
Will return you an IEnumerable of the complex types linked to the given id.
Example:
var lu = new Lookup<int, string>();
lu.Add(7, "Seven");
lu.Add(7, "SEVEN");
lu.Add(4, "Four");
lu.Add(7, "7");
lu.Add(4, "FOUR");
lu.Add(4, "FOUR");
Console.WriteLine(string.Join(", ", lu[7])); // "Seven, SEVEN, 7"
Console.WriteLine(string.Join(", ", lu[4])); // "Four, FOUR, FOUR"
foreach (var grp in lu)
{
int id = grp.Key;
foreach (var str in grp)
{
...
}
}
Try this way:
Dictionary<int, List<string>> dictName = new Dictionary<int, List<string>>();
dictName.Add(0, null);
dictName[0] = new List<string>();
dictName[0].Add("Hello");

C# - Removing Items from Dictionary in while loop

I have this and all seems to work fine but not sure why and if its valid.
Dictionary<string, List<string>> test = new Dictionary<string, List<string>>();
while (test.Count > 0)
{
var obj = test.Last();
MyMethod(obj);
test.Remove(obj.Key);
}
Update: Thanks for the answers, I have updated my code to explain why I don't do Dictionary.Clear();
I don't understand why you are trying to process all Dictonary entries in reverse order - but your code is OK.
It might be a bit faster to get a list of all Keys and process the entries by key instead of counting again and again...
E.G.:
var keys = test.Keys.OrderByDescending(o => o).ToList();
foreach (var key in keys)
{
var obj = test[key];
MyMethod(obj);
test.Remove(key);
}
Dictonarys are fast when they are accessed by their key value. Last() is slower and counting is not necessary - you can get a list of all (unique) keys.
There is nothing wrong with mutating a collection type in a while loop in this manner. Where you get into trouble is when you mutate a collection during a foreach block. Or more generally use a IEnumerator<T> after the underlying collection is mutated.
Although in this sample it would be a lot simpler to just call test.Clear() :)
That works, fine, since you're not iterating over the dictionary while removing items. Each time you check test.Count, it's like it's checking it from scratch.
That being said, the above code could be written much simpler and more effectively:
test.Clear();
It works because Count will be updated every time you remove an object. So say count is 3, test.Remove will decriment the count to 2, and so on, until the count is 0, then you will break out of the loop
Yes, this should be valid, but why not just call Dictionary.Clear()?
All you're doing is taking the last item in the collection and removing it until there are no more items left in the Dictionary.
Nothing out of the ordinary and there's no reason it shouldn't work (as long as emptying the collection is what you want to do).
So, you're just trying to clear the Dictionary, correct? Couldn't you just do the following?
Dictionary<string, List<string>> test = new Dictionary<string, List<string>>();
test.Clear();
This seems like it will work, but it looks extremely expensive. This would be a problem if you were iterating over it with a foreach loop (you can't edit collections while your iterating).
Dictionary.Clear() should do the trick (but you probably already knew that).
Despite your update, you can probably still use clear...
foreach(var item in test) {
MyMethod(item);
}
test.Clear()
Your call to .Last() is going to be extremely inefficient on a large dictionary, and won't guarantee any particular ordering of the processing regardless (the Dictionary is an unordered collection)
I used this code to remove items conditionally.
var dict = new Dictionary<String, float>
var keys = new String[dict.Count];
dict.Keys.CopyTo(keys, 0);
foreach (var key in keys) {
var v = dict[key];
if (condition) {
dict.Remove(key);
}

Categories

Resources