Collection was modified; enumeration operation may not execute.
I get that error when I run my program.
I have a dictionary and when I modify it I can't enumerate from it.
public void Render() {
foreach (var pair in players ) {
Main.SpriteBatch.DrawString(Main.BigFont, pair.Key, pair.Value, Color.White);
}
}
I tried modifying it at the value or removing it completely, then it must re-add it.
byte[] data = client.EndReceive(ar, ref ip);
string str_data = Encoding.ASCII.GetString(data);
string[] coords = str_data.Split(";".ToCharArray());
if (players.ContainsKey(coords[0])) {
players.Remove(coords[0]);
}
players.Add(coords[0], new Vector2(Int32.Parse(coords[1]), Int32.Parse(coords[2])));
You can also try to use an ordinary for loop instead of a foreach.
That way you can circumvent the warning, since you're not using the enumeration option.
For a dictionary you would do:
List<string/*or other datatype*/> keys = players.Keys.ToList();
for (int i = 0; i < keys.Count; i++)
{
Main.SpriteBatch.DrawString(Main.BigFont, keys[i], players[keys[i]], Color.White);
}
Does this suit your needs?
var ToBeDeleted = new List<player>(); //Or whatever type was the list players holding
if (players.ContainsKey(coords[0])) {
ToBeDeleted.Add(coords[0]);
}
foreach(var item in ToBeDeleted)
{
players.Remove(item);
}
You cannot modify (add, update or remove) any collection while you are iterating over it. It is restricted in c#.
You need to modify your code so that you keep any updation on the list seperate. You can keep a seperate record for any changes that you have made during the loop and merge after the loop.e.g
var itemsToDelete = new Dictionary<int,Player>();
then change your this line
if (players.ContainsKey(coords[0])) {
players.Remove(coords[0]);
}
to
if (players.ContainsKey(coords[0])) {
itemsToDelete.Add(coords[0]);
}
then after your loop
foreach (var key in itemsToDelete)
{
players.Remove(key);
}
Related
I have a code
foreach (DataColumn dataTableCol in this.dataTable.Columns)
{
bool columnFound = false;
foreach (GRTColumnView uiColumn in descriptor.UIColumns)
{
if (dataTableCol.ColumnName.Equals(uiColumn.Name))
{
columnFound = true;
break;
}
}
if (!columnFound)
{
if (this.dataTable.Columns.Contains(dataTableCol.ColumnName))
this.dataTable.Columns.Remove(dataTableCol.ColumnName);
}
}
I want to remove some "things" from collection if they aren't found in another collection.
When I run the above program, I get
Iteration may not execute as collection was modified
"Collection was modified" - Coz the remove must have been hit
What is the way to achieve such a thing then ?
What I can think of is make a note of all the "things" to remove and then
foreach( aThing in all_things_to_remove)
remove_from_collection(aThing)
But above doesn't seem a good way to me, as I have to do another looping and am using extra memory
In this specific case, where you're looping through a small collection containing a few columns, you can just create a new collection (via ToList()), so that you're not iterating over the same collection you're modifying:
foreach (var dataTableCol in dataTable.Columns.Cast<DataColumn>().ToList())
{
...
dataTable.Columns.Remove(dataTableCol.ColumnName);
}
The recommended way, especially if the collection is large, is to enumerate backwards:
for (var i = dataTable.Columns.Count - 1; i >= 0; i--)
{
...
dataTable.Columns.Remove(dataTable.Columns[i].ColumnName);
}
You cannot remove items from a collection while enumerating it with the foreach loop. Make a copy of the collection using Collection.ToArray() and run you foreach on the copy and remove your item from the actual collection.
Since DataTable.Columns does not have ToArray or ToList methods, you could use the CopyTo() method and copy the entire columns to a ColumnsArray.
If you do not want to create a copy, then you can use for loop instead of foreach loop. You could edit you code this way:
for (int i = 0; i < dataTable.Columns.Count; i++)
{
bool columnFound = false;
foreach (GRTColumnView uiColumn in descriptor.UIColumns)
{
if (dataTable.Columns[i].Name.Equals(uiColumn.Name))
{
columnFound = true;
break;
}
}
if (!columnFound)
{
if (this.dataTable.Columns.Contains(dataTableCol.ColumnName))
this.dataTable.Columns.Remove(dataTableCol.ColumnName);
}
}
the other way is lowering the index after removing column.
for (int i = 0; i < datatable.Columns.Count; i++)
{
if (datatable.Columns[i].ColumnName.Contains("Column"))
{
datatable.Columns.RemoveAt(i);
i--;
}
}
if (dt.Columns.Contains("RecordID")){
dt.Columns.Remove("RecordID");
dt.AcceptChanges();
}
Right now I have a dictionary being populated with an account as key, and a List as value. I believe my code is working to populate it. But my next step is to iterate through that List associated with a particularly key and do stuff with the list (get sums for each field). I am not that familiar with dictionaries so I am not sure how to access the values and perform an action. I would like to do this summation and print it out in my for each loop, when I exit the while loop.
1) If I could figure out how to access each field in DataRecords (inside the foreach loop), I could likely figure out how to do the summation.
2) Also looking for a way to print the values so I can see if it is even populated correctly.
static void Main(string[] args)
{
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
while (!r.EndOfStream)
{
if (control == "1")
{
// Need to add List<Datarecords> into dictionary...
if (vSummaryResults.ContainsKey(records.account))
{
vSummaryResults[records.account].Add(records);
}
else
{
vSummaryResults.Add(records.account, new List<DataRecord>());
vSummaryResults[records.account].Add(records);
}
}
}
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
vWriteFile.Close();
Console.ReadLine();
}
Here is my DataRecord class that I am using as the object in the List.
public class DataRecord
{
fields.....
}
For iterations over a dictionary, we use KeyValuePair:
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key;
List<DataRecord> list = kvp.Value;
Console.WriteLine("Key = {0}, contains {1} values:", key, list.Count);
foreach (DataRecord rec in list)
{
Console.WriteLine(" - Value = {0}", rec.ToString()); // or whatever you do to put list value on the output
}
}
You need another loop inside the first to get values in your list.
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
If you know the key:
foreach (List<DataRecord> rec in vSummaryResults[key])
{
foreach(DataRecord data in rec)
{
Console.WriteLine(data .YourProperty);
}
}
I made an example with a simple situation. Its a list of strings, but you can do the object.ToString() to get some tekst;
To loop over the list contained by the key you need to iterate over that list again that is what the 2nd foreach does.
Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
List<String> ls = new List<string>();
ls.Add("item1");
ls.Add("item2");
dictionary.Add("it1", ls);
dictionary.Add("it2", ls);
foreach (var item in dictionary)
{
foreach(var it in item.Value)
{
Console.WriteLine(it);
}
}
You have a dictionary
Dictionary<string, List<DataRecord>> vSummaryResults = new Dictionary<string, List<DataRecord>>();
You could do a
foreach (List<DataRecord> recs in vSummaryResults.Values)
{
foreach (DataRecord rec in recs)
Console.WriteLine(rec.Something);
}
You haven't specified what DataRecord looks like, but you would get a list of list. There's probably a lovely Linq expression that could do the same.
I understand it from reading your code, you have a dictionary where each key has a list of type DataRecord.
With your current loop
foreach (List<DataRecord> rec in vSummaryResults.Values)
{
Console.WriteLine(rec.); dictionary.
}
You looped through each List of type DataRecord. To access the data stored in each object in each list you will need to include another foreach loop to loop through the objects in the list.
foreach (var rec in vSummaryResults.Values)
{
// At this point we have access to each individual List<DataRecord>
foreach(var SingleDataRecordObj in rec)
Console.WriteLine(ingleDataRecordObj.membervariablename)
//From here we are able to list the individual variable member names of values that are in the DataRecord data type, showing all of the information in each list that is stored in the values of the dictionary
}
You can't modify the data in the foreach loop, but you could add them a more simple data structure to perform whatever commutation you wanted etc.
Here is the code for exactly what I needed to do. Working the way I need it to now, thanks for everyone's help.
int iSumOpen = 0;
foreach (KeyValuePair<string, List<DataRecord>> kvp in vSummaryResults)
{
string key = kvp.Key; //assigns key
List<DataRecord> list = kvp.Value; //assigns value
Console.WriteLine("Key = {0}", key);
iSumOpen = 0;
foreach (DataRecord rec in list)
{
if (vSummaryResults.ContainsKey(key))
{
iSumOpen += rec.open;
}
else
{
vSummaryResults.Add(key, list);
}
}
Console.WriteLine(iSumOpen);
}
Assuming I have some objects like this:
Class NetworkSwitch
{
private String _name;
String name { get {return _name;} set {_name=value;}}
Dictionary<int, VLAN> VLANDict = new Dictionary<int, NetworkSwitch>();
public List<CiscoSwitch> GetAllNeigbors()
{
List<CiscoSwitch> templist = new List<CiscoSwitch>();
foreach (KeyValuePair<int, CiscoVSAN> vlanpair in this.VLANDict)
{
templist.AddRange((vlanpair.Value.NeighborsList.Except(templist, new SwitchByNameComparer())).ToList());
}
return templist;
}
Class VLAN
{
private Int _VLANNum;
Int VLANNum {get {return _VLANNum ;} set {_VLANNum =value;}}
//a neighbor is another switch this switch is connected to in this VLAN
// the neighbor may not have all same VLANs
List<NetworkSwitch> Neighbors = new List<NetworkSwitch>();
}
the above is designed that way because two switches that are physically connected may not have all the same VLANs assigned. what I am attempting to do is step through the Neighbors list in each VLAN on a given switch and update the reference to another switch if the name matches one in an input list. Here is what I tried and it won't compile. I am wondering if LINQ can do it in place somehow, or if there is a better approach.
// intersect is the input list of NetworkSwitch objects
//MyNetworkSwitch is a previously created switch
foreach (NetworkSwitch ns in intersect)
{
foreach (KeyValuePair<int, VLAN> vlanpair in MyNetworSwitch.VLANDict)
{
foreach (CiscoSwitch neighbor in vlanpair.Value.Neighbors)
{ // this is the line that fails - I can't update neighbor as it is part of the foreach
if (ns.name == neighbor.name) { neighbor = ns; }
}
}
}
Another question - I added the method that gets all the neighbors for a NetworkSwitch object. Assuming I were to get that list, then update it with references to a different instance of the switch with the same name, would that update the reference in the VLAN for the NetworkSwitch object?
Something like this should work:
foreach (NetworkSwitch ns in intersect)
{
foreach (KeyValuePair<int, VLAN> vlanpair in ns.VLANDict)
{
if(vlanpair.Value.Neighbors.RemoveAll(n => n.name == ns.name) > 0)
vlanpair.Value.Neighbors.Add(ns);
}
}
Due to how IEnumerable works, changing the contents of an Enumerable while iterating over it is not a supported action.
You will either have to return a new list with the changed values and then update the original reference, or use a plain ol' for (...; ...; ...) loop.
I have this code that removes a player if the player is not alive, but I figured the problem is to do with the foreach loop. I've seen solutions involving making new lists, but I cannot see how I can apply it to my code. Can anyone please shed some light?
private Dictionary<int, Player> numPlayers = new Dictionary<int, Player>();
private void CheckPlayers()
{
foreach (Player player in numPlayers.Values)
{
if (!player.isAlive)
{
canvas.Children.Remove(player.hand);
numPlayers.Remove(player.id); // breaks here
}
}
}
Query the collection for the players to delete:
var playersToDelete = numPlayers.Values.Where(p => !p.isAlive).ToList();
Then delete the players:
foreach(var player in playersToDelete) {
canvas.Children.Remove(player.hand);
numPlayers.Remove(player.id);
}
You can't modify the collection you are iterating over with foreach. What you need to do is add the items you want to remove to a new list, then once that list is built remove them.
var dead = numPlayers.Values
.Where(p => !p.isAlive)
.ToList();
foreach(var player in dead)
{
canvas.Children.Remove(player.hand);
numPlayer.Remove(player.id);
}
You should remove the elements of a collection using a reverse for:
for(int i = numPlayers.Values.Count - 1; i <= 0; i--)
{
//Remove it.
}
How can I dissect or retrieve string values?
Here's the sample code that I'm working on now:
private void SplitStrings()
{
List<string> listvalues = new List<string>();
listvalues = (List<string>)Session["mylist"];
string[] strvalues = listvalues.ToArray();
for (int x = 0; x < strvalues.Length; x++)
{
}
}
Now that I'am able to retrieve list values in my session. How can I separately get the values of each list using foreach or for statement?
What I want to happen is to programmatically split the values of the strings depending on how many is in the list.
If you have a list of string values, you can do the following:
private void SplitStrings()
{
List<string> listValues = (List<string>) Session["mylist"];
// always check session values for null
if(listValues != null)
{
// go through each list item
foreach(string stringElement in listValues)
{
// do something with variable 'stringElement'
System.Console.WriteLine(stringElement);
}
}
}
Note that I test the result of casting the session and that I don't create a new list first-off, which is not necessary. Also note that I don't convert to an array, simply because looping a list is actually easier, or just as easy, as looping an array.
Note that you named your method SplitStrings, but we're not splitting anything. Did you mean to split something like "one;two;three;four" in a four-element list, based on the separator character?
I'm not sure what you're trying to obtain in this code, I don't know why you're converting your List to an Array.
You can loop through your listValues collection with a foreach block:
foreach(string value in listValues)
{
//do something with value, I.e.
Response.Write(value);
}
I don't know what's in the strings but you can start by simplifying. There is no point allocating a new List if you're going to overwrite it immediately.
private void SplitStrings()
{
List<string> list = (List<string>)Session["mylist"];
foreach(string value in list)
{
}
}
List listvalues = (List)Session["mylist"];
foreach (string s in listvalues)
{
//do what you want with s here
}