Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Remove items from a list

Posted on 2013-05-29
18
Medium Priority
?
316 Views
Last Modified: 2013-06-05
Ok guys I have a list
private List<String> _OptionCompare = new List<string>();

Open in new window


I am using a button click to populate the list...
 _OptionCompare.Add("RFQ Number");
            _OptionCompare.Add("ManPartNo");
            _OptionCompare.Add("Manufacturer");
            _OptionCompare.Add("CustPartNo");

Open in new window


I then have another button click that iterates the loop (removing from the loop the value of gridControl1.Columns[3].Tag.ToString() if it exists.
foreach (string summin in _OptionCompare)
            {
                System.Windows.MessageBox.Show(summin.ToString());

                while (_OptionCompare.Contains(gridControl1.Columns[3].Tag.ToString()))
                {
                    _OptionCompare.Remove(gridControl1.Columns[3].Tag.ToString());
                }

            }

Open in new window


This works if gridControl1.Columns[3].Tag.ToString() contains nothing in the list. However if it does then I get the error... Collection was modified; enumeration operation may not execute. on the for loop.

Any ideas?

Thanks,
Dean
0
Comment
Question by:deanlee17
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
  • 5
  • +1
18 Comments
 
LVL 9

Expert Comment

by:TvMpt
ID: 39204087
Have a look at the RemoveAll method of List<T>. It lets you remove an item based on a predicate.
0
 
LVL 42

Assisted Solution

by:Meir Rivkin
Meir Rivkin earned 668 total points
ID: 39204090
u can't amend the actual enumerator while u loop through it, u need to output the results  to another structure:
List<string> result = new List<string>();
string  str = gridControl1.Columns[3].Tag.ToString();
foreach (string summin in _OptionCompare)
            {
if(summin != str){
result.Add(summin);
}
}

//update the list
_OptionCompare = result;

Open in new window


u can do it in linq in one liner:
_OptionCompare= _OptionCompare.Where(str=>(str!=gridControl1.Columns[3].Tag.ToString())).ToList();

Open in new window

0
 

Author Comment

by:deanlee17
ID: 39204114
Sedgwick, that would make perfect sense.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 1332 total points
ID: 39204210
Why do you need the foreach at all? Your while loop alone should suffice in removing the items from the list.

You can switch to a reverse for loop: to remove items from the list:

e.g.

for(int i = _OptionCompare.Length - 1; i > -1; i--)
{
	string summin = _OptionCompare[i];
	
	System.Windows.MessageBox.Show(summin.ToString());

	if (summin == gridControl1.Columns[3].Tag.ToString()))
	{
	    _OptionCompare.RemoveAt(i);
	}
}

Open in new window

0
 

Author Comment

by:deanlee17
ID: 39204277
Kaufmed,

Why does for each work in reverse?

Ah so the while loop will iterate through the list anyway?
0
 
LVL 42

Expert Comment

by:Meir Rivkin
ID: 39204304
foreach uses readonly enumerator while for and index is not readonly.
that's why no exception is called when call Remove inside For scope, as oppose to foreach scope.
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 39204312
Because a for is not using an iterator. With a for you are indexing the list each time you want to access an item. The reason you go backwards is because as you remove items from the list, obviously the length of the list is going to decrease. A for loop's variable is initialized before the loop starts. If you go forward, you would (typically) initialize the variable to the length of the list. This only happens once. So if you start with 5 items in the list, and you remove the first 2, by the time you get to the 4th item, there are only 3 items left in the list. Your variable is now at "i = 4" (for example), but your list has a maximum index of 3. You will encounter an IndexOutOfRangeException.

Looping the list in reverse avoids encountering an exception because each time you remove a single item, the next iteration of the loop updates the loop variable with one less than the previous iteration (based on how you structure the loop). Each time the loop iterates, the loop variable will always point to a valid index within the list--provided you don't remove two items during any single iteration of the loop; then you would have problems.
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 39204320
that's why no exception is called when call Remove inside For scope
No, that's not why. I could easily generate an exception (not the same exact exception, but an exception nonetheless) by iterating the loop forwards, as I described above.
0
 
LVL 42

Expert Comment

by:Meir Rivkin
ID: 39204327
iterating backwards will yield no exception, that's why your example worked.
as oppose to loop forward, which yields exception when remove.
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 39204332
Ah so the while loop will iterate through the list anyway?
Given the usage in this discussion, "iterate" might not be the best term to use when discussing a while loop, but yes, it will. It's going to be less performant than a foreach or for loop since there is the potential for the while, based on how you've written it, to loop over the list multiple times.
0
 

Author Comment

by:deanlee17
ID: 39204364
Ok guys you have both given excellent feedback. So assuming each of you would have come across this how would you code it? in terms of clean code and performance.

The reason I am doing this is I have a row of dropdown boxes (containing 10 options) at the top of a datagrid, before an insert is done to the database I want to ensure that 4 items in the dropdowns have been allocated and obv add them back to the list if the combo is reset.

I hope that makes sense?
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 39204392
I'm a fan of LINQ for things like this--see sedgwick's earlier suggestion ( http:#a39204090 ). If you run into performance issues--not likely--then you can switch to a for approach.

I need to correct a statement I made earlier:
If you go forward, you would (typically) initialize the variable to the length of the list.
Going forwards, you wouldn't initialize the variable to the length of the list; you would do this when going backwards. In the forwards approach you would initialize the variable to zero--the first index of the list--and you would set the boundary condition to be that the variable is less than the length of the list.
0
 

Author Comment

by:deanlee17
ID: 39204409
Ah ok, are you a fan of Linq because its a simple 1 liner? Im assuming the difference in performance is minimal?
0
 
LVL 42

Expert Comment

by:Meir Rivkin
ID: 39204428
linq has other points that needs to take under consideration, specially when dealing with bug data structures.
in your case i'd go with linq cause its quick and neat.
0
 

Author Comment

by:deanlee17
ID: 39204484
Ok and whats the most efficient way (with Linq) to add an item into the list if it doesn't currently exist? ie when the combo box is reset?
0
 
LVL 42

Expert Comment

by:Meir Rivkin
ID: 39204525
to check if item is exists in list has a known complexity, for sorted and nonsorted lists.
so linq doesn't really assists you in this case.
besides List has a method called Contains which uses default equality comparer of the type, to check if item already exists in list.
List<T>.Contains Method
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 1332 total points
ID: 39204580
Ah ok, are you a fan of Linq because its a simple 1 liner? Im assuming the difference in performance is minimal?
Yes. Don't get me wrong, you can easily write complicated and obscure LINQ statments with ease. Nevertheless, LINQ statements can be written to effectively and concisely convey what it is they are doing.

LINQ is inherently slower based on what it does under the hood, but more often than not you won't notice the difference.

Ok and whats the most efficient way (with Linq) to add an item into the list if it doesn't currently exist? ie when the combo box is reset?

If you've got the same 4 options being repopulated within the CB, then I'd probably just maintain a class-level array that you can quickly pop into the list.

e.g.

private readonly string[] DEFAULT_CB_OPTIONS = { "RFQ Number", "ManPartNo", "Manufacturer", "CustPartNo" };

...


// Set defaults once cleared
_OptionCompare.AddRange(DEFAULT_CB_OPTIONS);

Open in new window


I don't see how you'll escape having to add each item back to the list once it's cleared--i.e. you're always going to have to call some form of Add*.
0
 

Author Comment

by:deanlee17
ID: 39204627
@kaufmed, Your example could be right and that all the combos could be reset at once if a new dataset is added to the datagrid. However sometimes a single CB could have its value reset , so this is when id like to check whats currently in the list and add the item back in (if its one of the 4 required options).

Im beginning to think I may have gone about this the wrong way.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
This course is ideal for IT System Administrators working with VMware vSphere and its associated products in their company infrastructure. This course teaches you how to install and maintain this virtualization technology to store data, prevent vuln…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…

636 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question