Modifying the contents of a Dictionary in foreach loop - c#

I am trying to update the contents of a C# Dictionary in a foreach loop, when a certain condition is met.
foreach (KeyValuePair<int, Corpus_22_04_2014_StreetTable_Row> entry in id_StreetNameDictionary)
{
if(something_happens())
{
Corpus_22_04_2014_StreetTable_Row r = entry.Value;
//Modify r
id_StreetNameDictionary[entry.Key] = r;
}
}
This throws an InvalidOperationException stating that "Collection was modified; enumeration operation may not execute.". It seems that we are not allowed to modify the contents of a Dictionary in foreach loop.
What can be a possible workaround to that?

You can simply use ToList on the dictionary to copy each key-value pair into a list. Then iterate over that list instead of Dictionary:
foreach (var entry in id_StreetNameDictionary.ToList())
{
if(something_happens())
{
Corpus_22_04_2014_StreetTable_Row r = entry.Value;
//Modify r
id_StreetNameDictionary[entry.Key] = r;
}
}

Create a list of all the keys and iterate that. For example:
foreach (var key in id_StreetNameDictionary.Keys.ToList())
{
if(something_happens())
{
var r = id_StreetNameDictionary[key];
//Modify r
id_StreetNameDictionary[key] = r;
}
}
This will be somewhat more memory efficient than creating a list of KeyValuePair structures from the dictionary.

Since it appears you really want to modify the row and not necessarily the Dictionary, then do so directly:
foreach (var entry in id_StreetNameDictionary)
{
if (something_happens())
{
((Corpus_22_04_2014_StreetTable_Row)entry.Value)["FieldToChange"] = newValue;
//...repeat for each field to change...you will be altering the row directly, no need to reassign it
}
}

Well I use the following workaround. Not very efficient maybe, but it does the work.
I declare three dictionaries:
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> id_StreetNameDictionary = new Dictionary<int, Corpus_22_04_2014_StreetTable_Row>();
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> tempDictionary = new Dictionary<int, Corpus_22_04_2014_StreetTable_Row>();
Dictionary<int, Corpus_22_04_2014_StreetTable_Row> swapBuffer;
I completely dump the old dictionary, with all modified and unmodified key/value pairs, into the tempDictionary. Then I swap both dictionaries and clear the unused one:
foreach (var entry in id_StreetNameDictionary)
{
Corpus_22_04_2014_StreetTable_Row row = id_StreetNameDictionary[entry.Key];
if (something_happens())
{
//Modify row
}
tempDictionary.Add(row.id, row);
}
swapBuffer = tempDictionary;
tempDictionary = id_StreetNameDictionary;
id_StreetNameDictionary = swapBuffer;
tempDictionary.Clear();

Related

How to dynamically remove key value pair from a dictionary if the key contains some substring?

I have an outer loop iterating over an array of substrings to be matched in the dictionary. In the inner loop I want to iterate over the dictionary and delete an entry whose key contains a substring.How to do this without getting "Collection was modified Exception"?
foreach (string outerKey in new string[] { "PAYERADDR_PAYERNAME", "RECADDR_RECNAME", "PAYERADDR_ADDR", "RECADDR_ADDR" })
{
foreach (var item in _generalWorksheetData.Where(kvp => kvp.Value.Contains(outerKey)).ToList())
{
_generalWorksheetData.Remove(item.Key);
}
}
You need a new collection:
List<string> todelete = dictionary.Keys.Where(k => k.Contains("substring")).ToList();
todelete.ForEach(k => dictionary.Remove(k));
or with a foreach:
foreach (string key in todelete)
dictionary.Remove(key); // safe to delete since it's a different collection
If Dictionary.Keys implemented IList instead of just ICollection you could access it in a backwards for-loop to remove them. But since there is no indexer you can't.
AFAIK, you can't. However you can store those pairs in a list and delete them in a separate loop from the first.
Just update your inner foreach as following:
foreach (var item in _generalWorksheetData.Keys.Where(kvp => kvp.Contains(outerKey)).ToList())
{
_generalWorksheetData.Remove(item);
}
Note that LINQ extension methods ToList and ToArray do allow you to modify collections.
List<string> sampleList = new List<string>();
sampleList.Add("1");
sampleList.Add("2");
sampleList.Add("3");
sampleList.Add("4");
sampleList.Add("5");
// Will not work
foreach (string item in sampleList)
{
sampleList.Remove(item);
}
// Will work
foreach (string item in sampleList.ToList())
{
sampleList.Remove(item);
}
Find match and remove the entries as below
var keysWithMatchingValues = dictionary.Where(d => d.Key.Contains("xyz"))
.Select(kvp => kvp.Key).ToList();
foreach(var key in keysWithMatchingValues)
dictionary.Remove(key);

How to access a nested Dictionary<> objects in a foreach loop

I have a nested Dictionary structure like this:
Dictionary<string, Dictionary<string, string>> dict;
I'm trying to access the elements using two foreach loops but the compiler won't let me use the following as the loop variable for my inner loop:
Dictionary<string, string>
This is what I have:
foreach (string key in dict.Keys) {
foreach (Dictionary<string, string> innerDict in dict[key]) {
// ...
}
}
The compiler says:
Cannot convert type 'System.Collections.Generic.KeyValuePair<string,string>'
to 'System.Collections.Generic.Dictionary<string,string>'
I can use KeyValuePair<string,string> in the inner loop, but I would like to access the dictionary object itself as a whole (so that I can do something like this: if (dict.ContainsKey(innerDict)) { ... })
The minimum code change to fix it is like this (but see the correct approach in the next code snippet in this answer):
Dictionary<string, Dictionary<string, string>> dict;
foreach (string key in dict.Keys)
{
foreach (var innerDict in dict[key].Select(k => k.Value))
{
}
}
Your problem was that when you enumerate over a dictionary, you get a sequence of Key/Value pairs. In your case, the Value was the inner dictionary, and it is that which you needed.
I'm using the Linq "Select()" operation to convert each key/value pair into just the value part, i.e. the dictionary which is the value in the key/value pair.
However, that's a long-winded and inefficient way to go about getting each inner dictionary along with its key. Here's how it should be done:
foreach (var item in dict)
{
string key = item.Key;
Dictionary<string, string> innerDict = item.Value;
// Do something with key and innerDict.
}
I'm assuming that you are trying to visit each inner dictionary in turn while knowning that inner dictionary's key in the outer dictionary.
Note that I only copied the values from item.Key and item.Value into local variables to illustrate their types. You could just use item.Key and item.Value directly, of course.
If you really only want the inner dictionaries themselves (and you don't need the key for each inner dictionary), you can just do it like so (as Nuffin suggested):
foreach (var innerDict in dict.Values)
{
// Use inner dictionary
}
That's because the value of the string key is not a list. Change the declaration of the Dictionary to Dictionary<string, List<Dictionary<string, string>>> dict; if that's what you want.
Or you could just grab the dictionary inside the first foreach loop like this:
Dictionary<string, string> val = dict[key];
and use it from there. But either way, you're trying to iterate against something that's not enumerable.
I think you may have the Dictionary defined like you want -you just don't need an inner loop.
You could just keep it short by using:
foreach (Dictionary<string, string> d in dict.Values) {
}
It works, no complaints from the compiler.
Also notice that your code doesn't work because in that context, dict[key] is not a collection of dictionaries, but a single dictionary.
I think you are misunderstanding the underlying Dictionary structure.
Dictionary<string, Dictionary<string, string>>
The above results in a parent containing a single dictionary object. When you attempt to use foreach over this object the compiler does not know what to do. It might be easier to understand if you use the following code
Dictionary<string,string> dictionaryObject;
foreach (string item in dictionaryObject)
{ }
The above will also result in the same error.
You can resolve your issue by iterating over the keys or values of the dictionary object, for example,
foreach (string key in dict.Keys)
{
foreach (string innerKey in dict[key].Keys)
{
System.Diagnostics.Debug.WriteLine(dict[key][innerKey]);
}
}
You will still have the dictionary to reference just like you wish, even when you use the KVP. Try this:
foreach (var outerKVP in dict {
foreach (var innerKVP in dict[outerKVP.Key]) {
var theString = dict[outerKVP.Key][innerKVP.Key];
}
}
foreach (Dictionary<string, string> innerDict in dict[key]) {
// ...
}
This fails because dict[key] is a Dictionary<string,string>, so enumerating it with foreach will yield elements of type KeyValuePair<string,string>.
If you want to access the inner dictionary, just do so and drop the foreach loop.
Dictionary<string, string> innerDict = dict[key];
Should be not so hard:
Dictionary<string, Dictionary<string, string>> dict = new Dictionary<string,Dictionary<string,string>>();
foreach (var kvp in dict)
{
var innerDict = kvp.Value;
foreach (var innerKvp in innerDict)
{
Console.WriteLine(kvp.Key + " " + innerKvp.Key + " " + innerKvp.Value);
}
}

Getting rid of duplicates inside List<> contained within a dictionary

I have the following dictionary.
Dictionary<string, List<string>> dictSubjects = new Dictionary<string, List<string>>();
and I am trying to get rid of potential duplicates residing within each list instace of the respective dictionary entry.
This is what I have tried but get and error along the lines of the list being read only
foreach (var kvp in dictSubjects)
{
lstSubjectsNoDupes.Clear();
for (int i = kvp.Value.Count - 1; i >= 0; i--)
{
if(lstSubjectsNoDupes.Contains(kvp.Value[i]))
{
lstSubjectsNoDupes.Add(kvp.Value[i]);
}
}
kvp.Value = lstSubjectsNoDupes;
}
How can I effectively get rid of potential duplicates within each list of my Dictionary?
The simplest way if you don't care too much about efficiency would be:
dictSubjects = dictSubjects.ToDictionary(pair => pair.Key,
pair => pair.Value.Distinct().ToList());
Alternatively, to update the existing dictionary:
foreach (var key in dictSubjects.Keys.ToList())
{
dictSubjects[key] = dictSubjects[key].Distinct().ToList();
}
Note the use of ToList here to avoid iterating over a view of a collection which is being modified. Without this, InvalidOperationException is thrown.
What about
foreach (var kvp in dictSubjects.ToList())
dictSubjects[kvp.Key] = kvp.Value.Distinct().ToList();

how to change Dictionary's value when enumerate it?

how to change Dictionary's value when enumerate it?
the following code doesn't work, because we can not change dictionary's value when enumerating it. Is there any way to get around it? Or NO WAY? Thanks
foreach (KeyValuePair<string, int> kvp in mydictionary)
{
if (otherdictionary.ContainsKey(kvp.Key))
{
mydictionary[kvp.Key] = otherdictionary[kvp.Key];
}
else
{
otherdictionary[kvp.Key] = mydictionary[kvp.Key];
}
}
The simplest way would be to take a copy first. As you only want the key value pairs, you might as well put them in a list rather than building a new dictionary though. Also, you can avoid doing quite as many lookups using TryGetValue.
var copy = myDictionary.ToList();
foreach (KeyValuePair<string, int> kvp in copy)
{
int otherValue;
if (otherdictionary.TryGetValue(kvp.Key, out otherValue))
{
mydictionary[kvp.Key] = otherValue;
}
else
{
otherdictionary[kvp.Key] = kvp.Value;
}
}
Make a copy of the values you need to enumerate over before you enumerate over them, then you can change the original source.
Since you don't actually use the value, you can change the code to this:
foreach (string key in mydictionary.Keys.ToArray())
if (otherdictionary.ContainsKey(key))
mydictionary[key] = otherdictionary[key];
else
otherdictionary[key] = mydictionary[key];
Note the use of .ToArray() there to make a temporary array copy of the key collection. This is now separate from the source dictionary, so you can change the dictionary all you want.
another option, copy the keys collection to an array and use it in for each loop -
string[] arr1 = new string[mydictionary.Count];
mydictionary.Keys.CopyTo(arr1,0);
foreach (string j in arr1)
{
if (otherdictionary.ContainsKey(j))
{
mydictionary[j] = otherdictionary[j];
}
else
{
otherdictionary[j] = mydictionary[j];
}
}

Loop through System.Collections.Generic.Dictionary via for statement

I have a quick question. Is there way to easy loop through System.Collections.Generic.Dictionary via for statement in C#?
Thanks in advance.
You can use foreach:
Dictionary<string,string> dictionary = new Dictionary<string,string>();
// ...
foreach (KeyValuePair<string,string> kv in dictionary)
{
string key = kv.Key;
string value = kv.Value;
}
Not in a reasonable way, no. You could use the Linq extension ElementAt:
for (int i = 0; i < dictionary.Keys.Count; i++)
{
Console.WriteLine(dictionary.ElementAt(i).Value);
}
...but I really don't see the point. Just use the regular foreach approach. If you for some reason need to keep track of an index while iterating, you can do that "on the side":
int index = 0;
foreach (var item in dictionary)
{
Console.WriteLine(string.Format("[{0}] - {1}", index, item.Value));
// increment the index
index++;
}
There are several ways.
Looping through the keys:
foreach(var key in myDictionary.Keys)
looping through values:
foreach(var value in myDic.Values)
looping through pairs:
foreach(KeyValuePair<K, V> p in myDic)
{
var key = p.Key;
var value = p.Value
}
No, for is mostly for collections with indices.
You can foreach over it easily, however.
If you are using Net 3.5 or later then you can use LINQ and a predecate to locate a specific Value or Values.
Dictionaries do not necessarily store their KeyValue pairs in order (either by entry order nor Key order).
Philippe's got it for foreach, though I usually simplify it to:
foreach (var pair in dictionary)
{
var key = pair.Key;
var value = pair.Value;
}
There's no way to loop through this collection of key-value pairs using a for loop because they aren't stored in order. You can loop through the keys or the values as collections though.
It can ofc be done, but it is a bit silly IMO
Dictionary<string,string> dictionary = new Dictionary<string, string>();
Dictionary<string, string>.Enumerator enumerator = dictionary.GetEnumerator();
for (int i = 0; i < attributeValues.Count;i++ )
{
KeyValuePair<string, string> current = enumerator.Current;
//do something usefull
enumerator.MoveNext();
}
the only thing gained by this is a (fairly useless) index, and if that is the actual goal, you are better served by something like this:
int currentIndex = 0;
foreach (KeyValuePair<string, string> keyValuePair in dictionary)
{
//do something usefull
currentIndex++;
}
If it does not have to be a "for"-loop, maybe using the Dictionary.GetEnumerator Method with a "while"-loop is an option - it is pretty easy as well IMHO:
var enumerator = d.GetEnumerator();
while (enumerator.MoveNext())
{
var pair = enumerator.Current;
b += pair.Value;
}
enumerator.Dispose();
code-snippet from C# Dictionary GetEnumerator
You can loop over the keys
for(int i = 0; i < myDictionary.Keys.Length; ++i)
myDictionary.Keys[i] ...
or the values
for(int i = 0; i < myDictionary.Values.Length; ++i)
myDictionary.Values[i] ...
Or both as Philippe shows

Categories

Resources