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;
}
}
Related
I have a dictionary that is being used in two threads, one is sending out UDP packets, one is receiving them. Both are keeping a common collection to see count outgoing and returning packets and hopefully keeping them at 0 difference :)
Now I'm iterating through the dictionary to update values and after iteration it errors. I do have a lock object in place, how could I solve this?
First Thread:
lock (retryListLock)
{
// loop through all known devices in the device list to build a counter if the device still lives
foreach(string key in retryList.Keys)
{
retryList[key] += 1;
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key);
}
}
}
}
Second Thread:
lock (retryListLock)
{
if (retryList.ContainsKey(frame.SerialNo))
retryList[frame.SerialNo] = 0;
else
retryList.Add(frame.SerialNo, 0);
}
I'm only getting the error after the first thread adds +1 to the value of that item, in the second iteration it errors out:
the collection has changed. enumeration operation may not execute (translated from Dutch)
How can I solve this? Obviously the Dictionary is the easiest to use for me in this case.
The problem is that you cannot change the dictionary in an iterator/foreach
foreach(string key in retryList.Keys)
{
retryList[key] += 1; // <-- The error happens here ! Do not alter the Dictionary during an iteration
if (retryList[key] > Retries)
{
DiscoveredDevice device = Devices.Find(d => d.SerialNo == key);
if (device != null)
{
OnDeviceRemoved(device);
Devices.Remove(device);
retryList.Remove(key); // <-- The error could also happen here ! Do not alter the Dictionary during an iteration
}
}
}
I found this question on stackoverflow which might help you
How to iterate through Dictionary and change values?
Here we find a statement from MSDN
The foreach statement is a wrapper around the enumerator, which allows
only reading from the collection, not writing to it.
With thanks to Bongo, taking the keys into a second list for iteration solved it:
List<string> Keys = new List<string>(retryList.Keys);
foreach(string key in Keys)
The error has nothing to do with the locks and multithreading.
Your enumerator (what foreach are using) is invalidated when you modify the very same data structure (the dictionary) on what the enumerator enumerates in the loop.
Solution:
You must first loop say with foreach, and remember practically in a list what you should remove. Then in a separate loop on the remembered keys, remove they from the dictionary.
This might be useful to you. Concurrent Dictionary
It's thread safe
Also change the for each to a reverse for loop
Something like this.
for (int x = max; x>=1; x--)
{
}
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.
I am trying to remove object while I am iterating through Collection. But I am getting exception. How can I achieve this?
Here is my code :
foreach (var gem in gems)
{
gem.Value.Update(gameTime);
if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
{
gems.Remove(gem.Key); // I can't do this here, then How can I do?
OnGemCollected(gem.Value, Player);
}
}
foreach is designed for iterating over a collection without modifing it.
To remove items from a collection while iterating over it use a for loop from the end to the start of it.
for(int i = gems.Count - 1; i >=0 ; i--)
{
gems[i].Value.Update(gameTime);
if (gems[i].Value.BoundingCircle.Intersects(Player.BoundingRectangle))
{
Gem gem = gems[i];
gems.RemoveAt(i); // Assuming it's a List<Gem>
OnGemCollected(gem.Value, Player);
}
}
If it's a dictionary<string, Gem> for example, you could iterate like this:
foreach(string s in gems.Keys.ToList())
{
if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle))
{
gems.Remove(s);
}
}
The easiest way is to do what #IV4 suggested:
foreach (var gem in gems.ToList())
The ToList() will convert the Dictionary to a list of KeyValuePair, so it will work fine.
The only time you wouldn't want to do it that way is if you have a big dictionary from which you are only removing relatively few items and you want to reduce memory use.
Only in that case would you want to use one of the following approaches:
Make a list of the keys as you find them, then have a separate loop to remove the items:
List<KeyType> keysToRemove = new List<KeyType>();
foreach (var gem in gems)
{
gem.Value.Update(gameTime);
if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
{
OnGemCollected(gem.Value, Player);
keysToRemove.Add(gem.Key);
}
}
foreach (var key in keysToRemove)
gems.Remove(key);
(Where KeyType is the type of key you're using. Substitute the correct type!)
Alternatively, if it is important that the gem is removed before calling OnGemCollected(), then (with key type TKey and value type TValue) do it like this:
var itemsToRemove = new List<KeyValuePair<TKey, TValue>>();
foreach (var gem in gems)
{
gem.Value.Update(gameTime);
if (gem.Value.BoundingCircle.Intersects(Player.BoundingRectangle))
itemsToRemove.Add(gem);
}
foreach (var item in itemsToRemove)
{
gems.Remove(item.Key);
OnGemCollected(item.Value, Player);
}
As the other answers say, a foreach is designed purely for iterating over a collection without modifying it as per the documenation:
The foreach statement is used to iterate through the collection to get
the desired information, but should not be used to change the contents
of the collection to avoid unpredictable side effects.
in order to do this you would need to use a for loop (storing the items of the collection you need to remove) and remove them from the collection afterwards.
However if you are using a List<T> you could do this:
lines.RemoveAll(line => line.FullfilsCertainConditions());
After going through all the answers, and being equally good. I faced a challenge where I had to modify a List and what I ended up doing worked quite well for me. So just in case anyone finds it useful. Can someone provide me feedback on how efficient it might be.
Action removeFromList;
foreach(var value in listOfValues){
if(whatever condition to remove is){
removeFromList+=()=>listOfValues.remove(value);
}
}
removeFromList?.Invoke();
removeFromList = null;
You should use the for loop instead of the foreach loop. Please refer here
Collections support foreach statement using Enumarator. Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.
Use for loop for collection modifying.
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
I have two dictionary personalizePatientChartDictionary and personalizePatientChartDictionaryOriginal. Both have same key but value can be different. I want to find out if there is any difference in value for a key. I have come up with the following function. Is there any better way of doing this? I am using .NET 4.0.
void CompareOriginalValues()
{
foreach (KeyValuePair<string, int> Origkvp in personalizePatientChartDictionaryOriginal)
{
foreach (KeyValuePair<string, int> kvp in personalizePatientChartDictionary)
{
if ((Origkvp.Key == kvp.Key) && (Origkvp.Value != kvp.Value))
{
hasDictionaryChanged = true;
break;
}
}
if (hasDictionaryChanged)
{
break;
}
}
}
foreach (var kvp in personalizePatientChartDictionaryOriginal)
{
int value;
if (personalizePatientChartDictionary.TryGetValue(kvp.Key, out value))
{
if (kvp.Value != value)
{
hasDictionaryChanged = true;
break;
}
}
}
Note that this code (and your original code) don't detect if there are keys in one dictionary that aren't present in the other. It only checks that the value associated with a particular key in the first dictionary is associated with the same key in the second dictionary, but only if that key actually exists in the second dictionary.
Seems good. But it would be good to return hasDictionaryChanged to indicate that it changed
You can do it using LINQ (don't forget to add "using System.Linq" to your usings)
bool hasDictionaryChanged = personalizePatientChartDictionaryOriginal.Except(personalizePatientChartDictionary).Count() > 0;
For more information about what you can do with LINQ, see 101 LINQ Samples.
It would be possible to write your own version of the dictionary class, inherit from dictionary and IComparable.
Then you could do dictionary1.Compare(dictionary2);
Here is a good resource for the ICompareable interface
http://msdn.microsoft.com/en-us/library/system.icomparable.aspx