Removing something from a list - c#

I am trying to remove something from a list using a counter but it is not working for me.
int i =0;
foreach(Rolls rl in rolls)
{
if(rl.getCourseId == courseId && rl.getStudentId == studentId)
{
rolls.RemoveAt(i) ;
}
i++;
}
Can anyone see why this might not work. Its gives me a run time exception:
"Collection was modified; enumeration operation may not execute."

Jonas explained why this won't work, but I thought I'd provide another option.
You can use List<T>.RemoveAll to remove all matching items in one call:
rolls.RemoveAll(rl => rl.getCourseId == courseId && rl.getStudentId == studentId);

You can't modify a collection while you're foreach-ing through it. Try using a regular for loop instead (or a while loop):
int i = 0;
while(i < myCollection.Count)
{
if(removeItem)
myCollection.RemoveAt(i);
else
++i;
}

You can't modify the collection as you iterate through it with foreach.
Try using a for loop like so
for(int i = 0; i < rolls.Length; i++) {

Foreach on a collection won't work like that. Try this:
for (int x = 0; x < rolls.Count; x++)
{
if(rolls[x].getCourseId == courseId && rolls[x].getStudentId == studentId)
{
rolls.RemoveAt(x);
--x; //since we removed an item, the index needs to be updated accordingly
}
}

you should do a loopback
for(int i=rolls.Count-1;i>=0;i--)
if(rolls[i].getCourseId == courseId && rolls[i].getStudentId == studentId)
rolls.RemoveAt(i)

Related

Iterating through a list is very slow, how to improve the performance

I have a method that iterate through a list and display the result of each type one followed by another meaning that I will display result from rd followed by result from cv followed by adz. But the actual method is very slow and it takes long time to retrieve back the results. what are the ways to improve the performance and will it matter using different data structure
private List<AllJobModel> GetAllJobModelsOrder(List<AllJobModel> result)
{
var countItems = result.Count;
List<AllJobModel> list = new List<AllJobModel>();
while (countItems != 0)
{
for (int i = 0; i < countItems; i++)
{
if (result.ElementAt(i).JobImage.Contains("rd"))
{
list.Add(result.ElementAt(i));
result.RemoveAt(i);
countItems--;
break;
}
}
for (int i = 0; i < countItems; i++)
{
if (result.ElementAt(i).JobImage.Contains("cv"))
{
list.Add(result.ElementAt(i));
result.RemoveAt(i);
countItems--;
break;
}
}
for (int i = 0; i < countItems; i++)
{
if (result.ElementAt(i).JobImage.Contains("adz"))
{
list.Add(result.ElementAt(i));
result.RemoveAt(i);
countItems--;
break;
}
}
for(int i =0; i < countItems; i++)
{
if((!result.ElementAt(i).JobImage.StartsWith("rd") && !result.ElementAt(i).JobImage.StartsWith("adz")) && !result.ElementAt(i).JobImage.StartsWith("cv"))
{
list.Add(result.ElementAt(i));
result.RemoveAt(i);
countItems--;
break;
}
}
}
return list;
}
This is a bad way to sort. You're effectively looping over the list 4 times, extracting specific groups of items each time. You also have a potential bug by removing items as you are iterating over the list. While there are many improvements you can make to your method, a better way would be to use OrderBy with the following sort condition:
list = result.OrderBy( m => m.JobImage.Contains("rd") ? 1 :
m.JobImage.Contains("cv") ? 2 :
m.JobImage.Contains("adz") ? 3 :
4)
.ToList();
Check out this link: https://cc.davelozinski.com/c-sharp/fastest-collection-for-string-lookups
Was very helpfull for me.
Regarding your specific problem. It looks like you're doing some filtering of the data. Linq has an easy way of doing that. I haven't test performance but if you can give me some example data ill try it for you. It could be something like this.
private List<AllJobModel> GetAllJobModelsOrder(List<AllJobModel> result)
{
return result.Where(x => x.JobImage.Contains("rd") || x.JobImage.Contains("cv") || x.JobImage.Contains("adz")).ToList();
}

How to remove multiple row from datagridview without using index?

I want to remove multiple row from datagridview,
I tried the below code, here row's are getting deleted based on index.
for (int m = 0; m < dataGridView3.Rows.Count - 1; m++)
{
if (dataGridView3.Rows[m].Cells[2].Value != null)
{
for (int n = 0; n < dataGridView2.Rows.Count - 1; n++)
{
if (dataGridView2.Rows[n].Cells[2].Value != null)
{
if (dataGridView2.Rows[n].Cells[2].Value.Equals(dataGridView3.Rows[m].Cells[2].Value) &&
dataGridView2.Rows[n].Cells[8].Value.Equals(dataGridView3.Rows[m].Cells[8].Value))
{
dataGridView2.Rows.RemoveAt(n);
//break;
}
}
}
}
}
here rows are not getting deleted properly, because index is changed after every single delete, so some records are missing out from loop.
can anyone help me how to solve this?
If you're going to remove items from the collection as you iterate through it like this, you'll need to work backwards through the collection of rows:
// start with the last row, and work towards the first
for (int n = dataGridView2.Rows.Count - 1; n >= 0; n--)
{
if (dataGridView2.Rows[n].Cells[2].Value != null)
{
if (dataGridView2.Rows[n].Cells[2].Value.Equals(dataGridView3.Rows[m].Cells[2].Value) &&
dataGridView2.Rows[n].Cells[8].Value.Equals(dataGridView3.Rows[m].Cells[8].Value))
{
dataGridView2.Rows.RemoveAt(n);
//break;
}
}
}
Alternatively, you could use LINQ to find your matches first, and then remove them:
var rowToMatch = dataGridView3.Rows[m];
var matches =
dataGridView2.Rows.Cast<DataGridViewRow>()
.Where(row => row.Cells[2].Value.Equals(rowToMatch.Cells[2].Value)
&& row.Cells[8].Value.Equals(rowToMatch.Cells[8].Value))
.ToList();
foreach (var match in matches)
dataGridView2.Rows.Remove(match);
Just to make it less of a maintenance head-ache, you might want to use the column name instead of the column index too... just a thought.

Index was outside the bounds of the array in CheckedListBox

I am getting an index error on my else if statement but I'm unable to find the reason for it.
What I am doing is going through a CheckedListBox, if no values are checked print an error else show the selected values in a MessageBox.
Can anybody help me? Thank you!
for (int i = 0; i < checkedListBox1.Items.Count; i++)
if (checkedListBox1.CheckedItems.Count == 0)
{
Empty.SetError(checkedListBox1, "Please select at Least One");
return;
}
else if (checkedListBox1.GetItemChecked(i))
{
MessageBox.Show(checkedListBox1.CheckedItems[i].ToString());
}
Move the Count-ckeck before the loop:
if (checkedListBox1.CheckedItems.Count == 0)
{
Empty.SetError(checkedListBox1, "Please select at Least One");
return;
}
But the important part is that you are looping all items. Then you check for every item if it is checked with GetItemChecked. That's fine, but then you use checkedListBox1.CheckedItems[i] which doesn't contain all items but only the checked items. That's why you get the Index was outside the bounds error.
Instead you just need to use that collection instead of looping all:
for(int i = 0; i < checkedListBox1.CheckedItems.Count; i++)
{
MessageBox.Show(checkedListBox1.CheckedItems[i].ToString());
}
You should change
i < checkedListBox1.Items.Count;
To:
i < checkedListBox1.CheckedItems.Count;
checkedListBox1.CheckedItems[i] is the problem. You loop through all the items, but indexing CheckedItems. So when you have 10 items and checked 2nd item and 8th item, CheckedItems will have only two items but you'll be accessing CheckedItems[7] that's why you get the exception.
Use CheckedItems collection to access checked items directly.
if (checkedListBox1.CheckedItems.Count == 0)
{
Empty.SetError(checkedListBox1, "Please select at Least One");
return;
}
foreach (var checkedItem in checkedListBox1.CheckedItems)
{
MessageBox.Show(checkedItem.ToString());
}
Why are you checking for CheckedItems.Count inside the for cycle?
Take the first part of the If clause outside of the For cycle.
At the end your code can look like that:
if (checkedListBox1.CheckedItems.Count == 0)
{
Empty.SetError(checkedListBox1, "Please select at Least One");
}
for (int i = 0; i < checkedListBox1.Items.Count; i++)
if (checkedListBox1.GetItemChecked(i))
{
MessageBox.Show(checkedListBox1.Items[i].ToString());
}

Remove all "0" values from List<int>

I'm simply looking for a way to remove all values that == 0 in a List(int).
Thanks.
Here are a few options:
Creating a new list based on the original list and filtering out the 0 values:
var newList = originalList.Where(i => i != 0).ToList();
Modifying the original list:
originalList.RemoveAll(i => i == 0);
The old-school, painful way (for funsies):
for (int i = 0; i < originalList.Length; i++)
{
if (originalList[i] == 0)
{
originalList.RemoveAt(i);
i--;
}
}
The really inefficient, traversing the list repeatedly way (don't do this):
while (originalList.Remove(0)) { }

Filtering elements of an array

I have an array as
That is, each item has its category in the following index.
I need all the items whose category are TotalNumbers and CurrentNumbers.
I tried
int i = 1;
foreach (string item in statsname)
{
//only number type stats are added to the comboboxes.
if ((statsname[i].ToUpperInvariant()==("TOTALNUMBER")) || ((statsname[i].ToUpperInvariant()==("CURRENTNUMBER"))))
{
comboBox1.Items.Add(statsname[i-1]);
i++;
i++;
}
comboBox1.SelectedIndex = 0;
}
Apparently this does not checks for what I need correctly.
How do I need to modify my codes to get what i need ?
Seems it's better to use a for loop instead of foreach:
for (int i = 1; i < statsname.Length; i += 2)
{
//only number type stats are added to the comboboxes.
if ((statsname[i].ToUpperInvariant()==("TOTALNUMBER")) || ((statsname[i].ToUpperInvariant()==("CURRENTNUMBER"))))
comboBox1.Items.Add(statsname[i-1]);
}
Linq comes to rescue!
var listItems = from s in statsname where s.Equals("TOTALNUMBER", StringComparison.InvariantCultureIgnoreCase) || s.Equals("CURRENTNUMBER", StringComparison.InvariantCultureIgnoreCase) select new ListItem(s);
comboBox1.AddRange(listItems);
Code not tested or compiled, but you can have an idea of what i said.
var filteredValues = Array.FindAll(source, s => s.ToUpperInvariant() == "TOTALNUMBER" ||
s.ToUpperInvariant() == "CURRENTNUMBER").ToList()
I am not sure why you are using index in an foreach loop. The below code should work for you
foreach (string item in statsname)
{
if ( item.ToUpper() == "TOTALNUMBER" || item.ToUpper() == "CURRENTNUMBER")
{
comboBox1.Items.Add(item);
}
}
comboBox1.SelectedIndex = 0;

Categories

Resources