This question already has answers here:
Collection was modified; enumeration may not execute error when removing a ListItem from a LIstBox
(10 answers)
Closed 8 years ago.
I have these nested Foreach :
foreach (var item1 in ocChoicesinItem)
{
foreach (var item2 in temp.ItemsInInvoiceChoices)
{
if (item1.ChoicesId == item2.ChoicesId)
ocChoicesinItem.Remove(item1);
}
}
The problem occur when remove item from ocChoicesinItem, gives me this error:
Is there any way to accomplish this?
Thanks in advance.
You need to add 'ToList' statements if you want to remove items in the collection :
foreach (var item1 in ocChoicesinItem.ToList())
{
foreach (var item2 in temp.ItemsInInvoiceChoices)
{
if (item1.ChoicesId == item2.ChoicesId)
ocChoicesinItem.Remove(item1);
}
}
You can't modify a collection while iterating that collection, as you are making your Enumerator invalid when calling MoveNext
Try:
public static class ExtensionMethods
{
public static int RemoveAll<T>(
this ObservableCollection<T> coll, Func<T, bool> condition)
{
var itemsToRemove = coll.Where(condition).ToList();
foreach (var itemToRemove in itemsToRemove)
{
coll.Remove(itemToRemove);
}
return itemsToRemove.Count;
}
}
ocChoicesinItem.RemoveAll(x => temp.ItemsInInvoiceChoices.Any(y => y.ChoicesId == x.ChoicesId);
Try something like
List<string> ocChoicesinItem = new List<string>{"One", "Two", "Three"};
List<string> ItemsInInvoiceChoices = new List<string> { "Three" };
ocChoicesinItem.RemoveAll(x => ItemsInInvoiceChoices.Contains(x));
Obviously I am using strings as I don't know what type your collections contain; you may have to compare the ID's in the predicate.
Related
I'm trying to make a leaderboard in Windows forms using c# but I can't come up with a solution.
Here is my current code.
lstleaderboard.Items.Add(int.Parse(txtScore.Text));
ArrayList Sorting = new ArrayList();
foreach (var o in lstleaderboard.Items)
{
Sorting.Add(o);
}
Sorting.Sort(new ReverseSort());
lstleaderboard.Items.Clear();
foreach (var o in Sorting)
{
lstleaderboard.Items.Add(o);
}
And I tried altering the code like this:
lstleaderboard.Items.Add(int.Parse(txtScore.Text));
ArrayList Sorting = new ArrayList();
foreach (var o in lstleaderboard.Items)
{
Sorting.Add(o);
}
Sorting.Sort(new ReverseSort());
lstleaderboard.Items.Clear();
foreach (var o in Sorting)
{
lstleaderboard.Items.Add(o + txtName.Text );
}
if (lstleaderboard.Items.Count == 11)
{
lstleaderboard.Items.RemoveAt(lstleaderboard.Items.Count - 1);
}
but this did not really work since it was then also sorting the names which messed up the scoreboard and it showed the wrong results, number one could be number three for example.
I am still learning so I apologize if my question is silly or my code is "weird"
Thanks
also here is my sorting class:
public class ReverseSort : IComparer
{
public int Compare(object x, object y)
{
return Comparer.Default.Compare(y, x);
}
}
So lstLeaderBoard is just list of integers, so you can safely use integer comparison, the way you did it, it just uses some default comparer on object type, which is far away from integer.
So simple LINQ OrderBy would suffice:
lstLeaderBoard.Items.Add(int.Parse(txtScore.Text));
var sortedItems = lstLeaderBoard.Items.Cast<int>().OrderBy(x => x);
lstLeaderBoard.Items.Clear();
foreach (var item in sortedItems)
lstLeaderBoard.Items.Add(item);
I have a dictionary defined as below ,
Dictionary<string, List<string>> dictionaryValues = new Dictionary<string, List<string>>();
Since I have a List of values I want iterate through them and find out what values have ="true" in them
Here is the source code what I have tried thus far
Would appreciate any help on this
List<string> listValues = new List<string>();
listValues.Add("value=true");
listValues.Add("value=false");
dictionaryValues.Add("Name", listValues);
foreach (var item in dictionaryValues)
{
foreach (var item in item.Value)
{
if (item.Contains("true"))
{
}
}
}
You can use the Values property on the dictionary. Also, you'll have to rename one of the "item" variables in either of the foreach loops.
See also msdn here.
foreach (List<string> items in dictionaryValues.Values)
{
foreach (string item in items)
{
if (item.Contains("true"))
{
}
}
}
I've also made it explicit what types the "items" and "item" are for clarity.
By using Linq you can do this with SelectMany and Where:
var valuesWithTrue = dictionaryValues.Values.SelectMany(x => x).Where(x => x.Contains("true"));
I am having some problems writing a recursive algorithm.
I have an item that affects other items.
Each of the affected items might affect other items...etc.
With a limited number of steps I might write:
var tempAffected = new List<Item>();
foreach(var item2 in item1.affectedItems)
{
if(item2.affectedItems > 0)
{
foreach(var item3 in item2.affectedItems)
{
if(item3.affectedItems > 0)
{
...
tempAffected.AddRange(item3.affectedItems)
tempAffected.Add(item3);
}
else
tempAffected.AddItem(item3);
}
}
else
tempAffected.AddItem(item2);
}
But I would like something recursive.
Any help would be appreciated.
EDIT
The final code ended up looking like this, after a few modifications in my code.
var tempAffected = new List<HSGameItem>();
var stack = new Stack<HSGameItem>(affected);
Func<HSGameItem, List<HSGameItem>> affectedForItem = item => {
if (item.booster.accounted)
return new List<HSGameItem> ();
item.booster.accounted = true;
return item.booster.affected;
};
while(stack.Count > 0)
{
var childrenParent = stack.Pop();
foreach (var child in affectedForItem(childrenParent))
{
tempAffected.AddUnique(child);
stack.Push(child);
}
}
tempAffected.ForEach(x => x.state.Matched(mType, length));
I had to mark every item that i already affected as "accounted" to make sure i wouldn't check it again.
So basically you want to collect all affected items into a temporary list called TempAffected, right?
Then you could do:
public List<Item> tempAffected = new List<Item>();
AddAffectedToDerived(item1, tempAffected);
private AddAffectedToDerived(Item root, List<Item> derived)
{
if (root.AffectedItems != null)
{
foreach(Item itemX in root.AffectedItems)
{
AddAffectedToDerived(itemX);
}
}
derived.Add(root);
}
That should do the trick for you.
Mind you, if your data structures are very large, you may want to use an iterative approach rather than a recursive instead because of the risk of stack overflow.
IMHO, the simplest implementation might look something like this:
IEnumerable<Item> GetAffectedItems(Item item)
{
foreach (Item affectedItem in item.affectedItems)
{
foreach (Item subItem in GetAffectedItems(affectedItem))
{
yield return subItem;
}
}
yield return item;
}
That said, note that the above will instantiate a large number of iterators (but at least that's better than creating a lot of copies of the data itself!). It's simple to write, but may not be as efficient as some other mechanism for enumerating all of the affected items.
As an example, an alternative would be to just build a List<Item> as you recurse (more similar to your original example):
List<Item> GetAffectedItems(Item item)
{
List<Item> list = new List<Item>();
GetAffectedItems(item, list);
return list;
}
void GetAffectedItems(Item item, List<Item> list)
{
foreach (Item affectedItem in item.affectedItems)
{
GetAffectedItems(affectedItem, list);
}
list.Add(item);
}
When running my code i put several string on different lines of the textbox but it breaks saying there is a Null Exception Error on "Items.Add(item)" I am not sure why I am getting
this error because in visual studio the string in the variable item is not null it contains
a return character through so I am not sure if that is an issue.. for example item = "uno\r". Also, Items is a list of strings. Does anyone know why I keep getting this Null Exception?
public List<string> Items;
public void getItemsFromTextBox(TextBox textbox)
{
string[] lines = textbox.Text.Split('\n');
foreach (string item in lines)
{
if (!String.IsNullOrWhiteSpace(item))
Items.Add(item);
}
}
You have not initialized your list, it's null! Add
public List<String> Items = new List<String>();
You must create instance of Items list:
public void getItemsFromTextBox(TextBox textbox)
{
Items = new List<string>();
string[] lines = textbox.Text.Split('\n');
foreach (string item in lines)
{
if (!String.IsNullOrWhiteSpace(item))
Items.Add(item);
}
}
Just try with following code.I guess your Items list is global one and shared list .so better to check that List is initialize or if not then initialize first and do the rest of the thing.
public List<string> Items;
public void getItemsFromTextBox(TextBox textbox)
{
if(null == Items)
{
Items = new List<string>();
}
foreach (string item in textbox.Text.Split('\n'))
{
if (!String.IsNullOrWhiteSpace(item))
Items.Add(item);
}
}
You must have create an instance of List Items.
use
public List<String> Items = new List<String>();
or use the below code
public void getItemsFromTextBox(TextBox textbox)
{
List<string> Items = !string.IsNullOrWhiteSpace(textbox.Text) ? textbox.Text.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List<string>();
}
Make sure that you have instantiated "Items".
I have a hashset in C# that I'm removing from if a condition is met while iterating though the hashset and cannot do this using a foreach loop as below.
foreach (String hashVal in hashset)
{
if (hashVal == "somestring")
{
hash.Remove("somestring");
}
}
So, how can I remove elements while iterating?
Use the RemoveWhere method of HashSet instead:
hashset.RemoveWhere(s => s == "somestring");
You specify a condition/predicate as the parameter to the method. Any item in the hashset that matches the predicate will be removed.
This avoids the problem of modifying the hashset whilst it is being iterated over.
In response to your comment:
's' represents the current item being evaluated from within the hashset.
The above code is equivalent to:
hashset.RemoveWhere(delegate(string s) {return s == "somestring";});
or:
hashset.RemoveWhere(ShouldRemove);
public bool ShouldRemove(string s)
{
return s == "somestring";
}
EDIT:
Something has just occurred to me: since HashSet is a set that contains no duplicate values, just calling hashset.Remove("somestring") will suffice. There is no need to do it in a loop as there will never be more than a single match.
You can't remove items from a collection while looping over it with an enumerator. Two approaches to solve this are:
Loop backwards over the collection using a regular indexed for-loop (which I believe is not an option in the case of a HashSet)
Loop over the collection, add items to be removed to another collection, then loop over the "to-be-deleted"-collection and remove the items:
Example of the second approach:
HashSet<string> hashSet = new HashSet<string>();
hashSet.Add("one");
hashSet.Add("two");
List<string> itemsToRemove = new List<string>();
foreach (var item in hashSet)
{
if (item == "one")
{
itemsToRemove.Add(item);
}
}
foreach (var item in itemsToRemove)
{
hashSet.Remove(item);
}
I would avoid using two foreach loop - one foreach loop is enough:
HashSet<string> anotherHashSet = new HashSet<string>();
foreach (var item in hashSet)
{
if (!shouldBeRemoved)
{
anotherSet.Add(item);
}
}
hashSet = anotherHashSet;
For people who are looking for a way to process elements in a HashSet while removing them, I did it the following way
var set = new HashSet<int> {1, 2, 3};
while (set.Count > 0)
{
var element = set.FirstOrDefault();
Process(element);
set.Remove(element);
}
there is a much simpler solution here.
var mySet = new HashSet<string>();
foreach(var val in mySet.ToArray() {
Console.WriteLine(val);
mySet.Remove(val);
}
.ToArray() already creates a copy for you. you can loop to your hearts content.
Usually when I want to iterate over something and remove values I use:
For (index = last to first)
If(ShouldRemove(index)) Then
Remove(index)