How to delete duplicate items in listview? - c#

Well, I need to check if there exists duplicate items inside listview on my app, but... I don't know how.
The way to detect this is by checking the field "Tag", if they are the same, then delete the item.

A good way to find duplicates is to use a temporary hashset. This gives you an O(n) O(n log n) algorithm (see Rick Sladkeys comments) to detect duplicates. Example:
var tags = new HashSet<string>();
var duplicates = new List<Item>();
foreach(Item item in listView.Items)
{
// HashSet.Add() returns false if it already contains the key.
if(!tags.Add(item.Tag)
duplicates.Add(item);
}
[Remove duplicates here]

Used nested for loops to go through and check each item against each other item.
//tag duplicates for removal
List<Item> toRemove = new List<Item>();
foreach(Item item1 in listView.Items)
{
foreach(Item item2 in listView.Items)
{
//compare the two items
if(item1.Tag == item2.Tag)
toRemove.Add(item2);
}
}
//remove duplicates
foreach(Item item in toRemove)
{
listView.Items.Remove(item);
}
You'll have to tweak the syntax for your code, but that's the basic idea behind it. Also, there are optimizations that could probably be made to it, but don't worry about those yet.

None of the above helped me, so I thought I'd post what I came up with in case someone else is having this issue.
myListView is a ListView, sorted alphabetically (so duplicates in this case are adjacent). You could sort it programatically beforehand if you wanted.
myListView.Sorting = SortOrder.Ascending;
Anyway this is fairly simplistic but I hope it helps someone!
for (int i = 0; i < myListView.Items.Count - 1; i++)
{
if (myListView.Items[i].Tag == myListVIew.Items[i + 1].Tag)
{
myListView.Items[i + 1].Remove();
}
}

If you have a lot of items then you can use a HashSet to keep the performance acceptable.
Loop over the items starting with the HashSet empty. For each item check if the tag is in the HashSet. If so this is a duplicate. If not add the tag to the HashSet.
This approach avoids an N^2 algorithm which is what you get with a nested loop. The HashSet makes the algorithm linear complexity providing the removal phase is carefully implemented. Of course this may not matter to you depending on how many items you have. If the list is small use nested loops and keep it simple.

If you are comparing duplicated Items based on specific columns you should simply use:
if(listview.Items.Find(SearchQuery).Count > 0)
{
//remove duplicates from list...
}
but you should name every item in the list when you fill up the listview..
for example if I want to search for duplicate items in column 1+2+5 I'd name the whole row like:
myItemName.Name = column1.Text + "_" + column2.Text + "_" + column5.Text;
and then perform the above "if statement"..

I would like to offer my solution using a Dictionary for future reference:
(you will edit for your own "Colums" (subitems), Simply read the code to understand.
I used the below to remove "Dups" in a listview on a button click, i am searching subitem you can edit code for your own use...
uses dictionary and a little easy "update" class i wrote.
private void removeDupBtn_Click(object sender, EventArgs e)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
int num = 0;
while (num <= listView1.Items.Count)
{
if (num == listView1.Items.Count)
{
break;
}
if (dict.ContainsKey(listView1.Items[num].SubItems[1].Text).Equals(false))
{
dict.Add(listView1.Items[num].SubItems[1].Text, ListView1.Items[num].SubItems[0].Text);
}
num++;
}
updateList(dict, listView1);
}
and using a little updateList() class...
private void updateList(Dictionary<string, string> dict, ListView list)
{
#region Sort
list.Items.Clear();
string[] arrays = dict.Keys.ToArray();
int num = 0;
while (num <= dict.Count)
{
if (num == dict.Count)
{
break;
}
ListViewItem lvi;
ListViewItem.ListViewSubItem lvsi;
lvi = new ListViewItem();
lvi.Text = dict[arrays[num]].ToString();
lvi.ImageIndex = 0;
lvi.Tag = dict[arrays[num]].ToString();
lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = arrays[num];
lvi.SubItems.Add(lvsi);
list.Items.Add(lvi);
list.EndUpdate();
num++;
}
#endregion
}
Good luck!

int J = 0;
In this simple code we will remove duplicates from a loop which will take the first item and compare it with the items bellow, so if it exists you can remove the above one or the second one
foreach (ListViewItem item1 in listView1.Items)
{
//J+1 to do not repeat the list from first and remove itself just take a look on next items
for (int i=J+1;i<listView1.Items.Count-1;i++)
{
//i compare two subitems that must be unique in my list
if (listView1.Items[J].SubItems[1].ToString() == listView1.Items[i].SubItems[1].ToString())
// listView1.Items.RemoveAt(i); // remove the second one
listView1.Items.RemoveAt(J); // remove the first one and keep the second
}
J++;
}

Related

How to iterate over a list<T> and alter it at the same time? [duplicate]

I am looking for a better pattern for working with a list of elements which each need processed and then depending on the outcome are removed from the list.
You can't use .Remove(element) inside a foreach (var element in X) (because it results in Collection was modified; enumeration operation may not execute. exception)... you also can't use for (int i = 0; i < elements.Count(); i++) and .RemoveAt(i) because it disrupts your current position in the collection relative to i.
Is there an elegant way to do this?
Iterate your list in reverse with a for loop:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
Example:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
Alternately, you can use the RemoveAll method with a predicate to test against:
safePendingList.RemoveAll(item => item.Value == someValue);
Here's a simplified example to demonstrate:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
foreach (var item in list.ToList()) {
list.Remove(item);
}
If you add ".ToList()" to your list (or the results of a LINQ query), you can remove "item" directly from "list" without the dreaded "Collection was modified; enumeration operation may not execute." error. The compiler makes a copy of "list", so that you can safely do the remove on the array.
While this pattern is not super efficient, it has a natural feel and is flexible enough for almost any situation. Such as when you want to save each "item" to a DB and remove it from the list only when the DB save succeeds.
A simple and straightforward solution:
Use a standard for-loop running backwards on your collection and RemoveAt(i) to remove elements.
Reverse iteration should be the first thing to come to mind when you want to remove elements from a Collection while iterating over it.
Luckily, there is a more elegant solution than writing a for loop which involves needless typing and can be error prone.
ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
foreach (int myInt in test.Reverse<int>())
{
if (myInt % 2 == 0)
{
test.Remove(myInt);
}
}
Using the ToArray() on a generic list allows you to do a Remove(item) on your generic List:
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
Select the elements you do want rather than trying to remove the elements you don't want. This is so much easier (and generally more efficient too) than removing elements.
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
I wanted to post this as a comment in response to the comment left by Michael Dillon below, but it's too long and probably useful to have in my answer anyway:
Personally, I'd never remove items one-by-one, if you do need removal, then call RemoveAll which takes a predicate and only rearranges the internal array once, whereas Remove does an Array.Copy operation for every element you remove. RemoveAll is vastly more efficient.
And when you're backwards iterating over a list, you already have the index of the element you want to remove, so it would be far more efficient to call RemoveAt, because Remove first does a traversal of the list to find the index of the element you're trying to remove, but you already know that index.
So all in all, I don't see any reason to ever call Remove in a for-loop. And ideally, if it is at all possible, use the above code to stream elements from the list as needed so no second data structure has to be created at all.
Using .ToList() will make a copy of your list, as explained in this question:
ToList()-- Does it Create a New List?
By using ToList(), you can remove from your original list, because you're actually iterating over a copy.
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
If the function that determines which items to delete has no side effects and doesn't mutate the item (it's a pure function), a simple and efficient (linear time) solution is:
list.RemoveAll(condition);
If there are side effects, I'd use something like:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
This is still linear time, assuming the hash is good. But it has an increased memory use due to the hashset.
Finally if your list is only an IList<T> instead of a List<T> I suggest my answer to How can I do this special foreach iterator?. This will have linear runtime given typical implementations of IList<T>, compared with quadratic runtime of many other answers.
As any remove is taken on a condition you can use
list.RemoveAll(item => item.Value == someValue);
List<T> TheList = new List<T>();
TheList.FindAll(element => element.Satisfies(Condition)).ForEach(element => TheList.Remove(element));
You can't use foreach, but you could iterate forwards and manage your loop index variable when you remove an item, like so:
for (int i = 0; i < elements.Count; i++)
{
if (<condition>)
{
// Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
elements.RemoveAt(i--);
}
}
Note that in general all of these techniques rely on the behaviour of the collection being iterated. The technique shown here will work with the standard List(T). (It is quite possible to write your own collection class and iterator that does allow item removal during a foreach loop.)
For loops are a bad construct for this.
Using while
var numbers = new List<int>(Enumerable.Range(1, 3));
while (numbers.Count > 0)
{
numbers.RemoveAt(0);
}
But, if you absolutely must use for
var numbers = new List<int>(Enumerable.Range(1, 3));
for (; numbers.Count > 0;)
{
numbers.RemoveAt(0);
}
Or, this:
public static class Extensions
{
public static IList<T> Remove<T>(
this IList<T> numbers,
Func<T, bool> predicate)
{
numbers.ForEachBackwards(predicate, (n, index) => numbers.RemoveAt(index));
return numbers;
}
public static void ForEachBackwards<T>(
this IList<T> numbers,
Func<T, bool> predicate,
Action<T, int> action)
{
for (var i = numbers.Count - 1; i >= 0; i--)
{
if (predicate(numbers[i]))
{
action(numbers[i], i);
}
}
}
}
Usage:
var numbers = new List<int>(Enumerable.Range(1, 10)).Remove((n) => n > 5);
However, LINQ already has RemoveAll() to do this
var numbers = new List<int>(Enumerable.Range(1, 10));
numbers.RemoveAll((n) => n > 5);
Lastly, you are probably better off using LINQ's Where() to filter and create a new list instead of mutating the existing list. Immutability is usually good.
var numbers = new List<int>(Enumerable.Range(1, 10))
.Where((n) => n <= 5)
.ToList();
Using Remove or RemoveAt on a list while iterating over that list has intentionally been made difficult, because it is almost always the wrong thing to do. You might be able to get it working with some clever trick, but it would be extremely slow. Every time you call Remove it has to scan through the entire list to find the element you want to remove. Every time you call RemoveAt it has to move subsequent elements 1 position to the left. As such, any solution using Remove or RemoveAt, would require quadratic time, O(n²).
Use RemoveAll if you can. Otherwise, the following pattern will filter the list in-place in linear time, O(n).
// Create a list to be filtered
IList<int> elements = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
// Filter the list
int kept = 0;
for (int i = 0; i < elements.Count; i++) {
// Test whether this is an element that we want to keep.
if (elements[i] % 3 > 0) {
// Add it to the list of kept elements.
elements[kept] = elements[i];
kept++;
}
}
// Unfortunately IList has no Resize method. So instead we
// remove the last element of the list until: elements.Count == kept.
while (kept < elements.Count) elements.RemoveAt(elements.Count-1);
I would reassign the list from a LINQ query that filtered out the elements you didn't want to keep.
list = list.Where(item => ...).ToList();
Unless the list is very large there should be no significant performance problems in doing this.
The best way to remove items from a list while iterating over it is to use RemoveAll(). But the main concern written by people is that they have to do some complex things inside the loop and/or have complex compare cases.
The solution is to still use RemoveAll() but use this notation:
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
By assuming that predicate is a Boolean property of an element, that if it is true, then the element should be removed:
int i = 0;
while (i < list.Count())
{
if (list[i].predicate == true)
{
list.RemoveAt(i);
continue;
}
i++;
}
In C# one easy way is to mark the ones you wish to delete then create a new list to iterate over...
foreach(var item in list.ToList()){if(item.Delete) list.Remove(item);}
or even simpler use linq....
list.RemoveAll(p=>p.Delete);
but it is worth considering if other tasks or threads will have access to the same list at the same time you are busy removing, and maybe use a ConcurrentList instead.
I wish the "pattern" was something like this:
foreach( thing in thingpile )
{
if( /* condition#1 */ )
{
foreach.markfordeleting( thing );
}
elseif( /* condition#2 */ )
{
foreach.markforkeeping( thing );
}
}
foreachcompleted
{
// then the programmer's choices would be:
// delete everything that was marked for deleting
foreach.deletenow(thingpile);
// ...or... keep only things that were marked for keeping
foreach.keepnow(thingpile);
// ...or even... make a new list of the unmarked items
others = foreach.unmarked(thingpile);
}
This would align the code with the process that goes on in the programmer's brain.
foreach(var item in list.ToList())
{
if(item.Delete) list.Remove(item);
}
Simply create an entirely new list from the first one. I say "Easy" rather than "Right" as creating an entirely new list probably comes at a performance premium over the previous method (I haven't bothered with any benchmarking.) I generally prefer this pattern, it can also be useful in overcoming Linq-To-Entities limitations.
for(i = list.Count()-1;i>=0;i--)
{
item=list[i];
if (item.Delete) list.Remove(item);
}
This way cycles through the list backwards with a plain old For loop. Doing this forwards could be problematic if the size of the collection changes, but backwards should always be safe.
Just wanted to add my 2 cents to this in case this helps anyone, I had a similar problem but needed to remove multiple elements from an array list while it was being iterated over. the highest upvoted answer did it for me for the most part until I ran into errors and realized that the index was greater than the size of the array list in some instances because multiple elements were being removed but the index of the loop didn't keep track of that. I fixed this with a simple check:
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
There is an option that hasn't been mentioned here.
If you don't mind adding a bit of code somewhere in your project, you can add and extension to List to return an instance of a class that does iterate through the list in reverse.
You would use it like this :
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
And here is what the extension looks like:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
This is basically list.Reverse() without the allocation.
Like some have mentioned you still get the drawback of deleting elements one by one, and if your list is massively long some of the options here are better. But I think there is a world where someone would want the simplicity of list.Reverse(), without the memory overhead.
Copy the list you are iterating. Then remove from the copy and interate the original. Going backwards is confusing and doesn't work well when looping in parallel.
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
I would do like this
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
OUTPUT
Fred Jones
Billy TheKid
I found myself in a similar situation where I had to remove every nth element in a given List<T>.
for (int i = 0, j = 0, n = 3; i < list.Count; i++)
{
if ((j + 1) % n == 0) //Check current iteration is at the nth interval
{
list.RemoveAt(i);
j++; //This extra addition is necessary. Without it j will wrap
//down to zero, which will throw off our index.
}
j++; //This will always advance the j counter
}
The cost of removing an item from the list is proportional to the number of items following the one to be removed. In the case where the first half of the items qualify for removal, any approach which is based upon removing items individually will end up having to perform about N*N/4 item-copy operations, which can get very expensive if the list is large.
A faster approach is to scan through the list to find the first item to be removed (if any), and then from that point forward copy each item which should be retained to the spot where it belongs. Once this is done, if R items should be retained, the first R items in the list will be those R items, and all of the items requiring deletion will be at the end. If those items are deleted in reverse order, the system won't end up having to copy any of them, so if the list had N items of which R items, including all of the first F, were retained,
it will be necessary to copy R-F items, and shrink the list by one item N-R times. All linear time.
My approach is that I first create a list of indices, which should get deleted. Afterwards I loop over the indices and remove the items from the initial list. This looks like this:
var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
Trace the elements to be removed with a property, and remove them all after process.
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = false;
foreach (MyProperty currObj in _Group)
{
// here it is supposed that you decide the "remove conditions"...
cond = true; // set true or false...
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
myList.RemoveAt(i--);
simples;

c#: Remove item from List and continue Foreach loop [duplicate]

I am looking for a better pattern for working with a list of elements which each need processed and then depending on the outcome are removed from the list.
You can't use .Remove(element) inside a foreach (var element in X) (because it results in Collection was modified; enumeration operation may not execute. exception)... you also can't use for (int i = 0; i < elements.Count(); i++) and .RemoveAt(i) because it disrupts your current position in the collection relative to i.
Is there an elegant way to do this?
Iterate your list in reverse with a for loop:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
Example:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
Alternately, you can use the RemoveAll method with a predicate to test against:
safePendingList.RemoveAll(item => item.Value == someValue);
Here's a simplified example to demonstrate:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
foreach (var item in list.ToList()) {
list.Remove(item);
}
If you add ".ToList()" to your list (or the results of a LINQ query), you can remove "item" directly from "list" without the dreaded "Collection was modified; enumeration operation may not execute." error. The compiler makes a copy of "list", so that you can safely do the remove on the array.
While this pattern is not super efficient, it has a natural feel and is flexible enough for almost any situation. Such as when you want to save each "item" to a DB and remove it from the list only when the DB save succeeds.
A simple and straightforward solution:
Use a standard for-loop running backwards on your collection and RemoveAt(i) to remove elements.
Reverse iteration should be the first thing to come to mind when you want to remove elements from a Collection while iterating over it.
Luckily, there is a more elegant solution than writing a for loop which involves needless typing and can be error prone.
ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
foreach (int myInt in test.Reverse<int>())
{
if (myInt % 2 == 0)
{
test.Remove(myInt);
}
}
Using the ToArray() on a generic list allows you to do a Remove(item) on your generic List:
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
Select the elements you do want rather than trying to remove the elements you don't want. This is so much easier (and generally more efficient too) than removing elements.
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
I wanted to post this as a comment in response to the comment left by Michael Dillon below, but it's too long and probably useful to have in my answer anyway:
Personally, I'd never remove items one-by-one, if you do need removal, then call RemoveAll which takes a predicate and only rearranges the internal array once, whereas Remove does an Array.Copy operation for every element you remove. RemoveAll is vastly more efficient.
And when you're backwards iterating over a list, you already have the index of the element you want to remove, so it would be far more efficient to call RemoveAt, because Remove first does a traversal of the list to find the index of the element you're trying to remove, but you already know that index.
So all in all, I don't see any reason to ever call Remove in a for-loop. And ideally, if it is at all possible, use the above code to stream elements from the list as needed so no second data structure has to be created at all.
Using .ToList() will make a copy of your list, as explained in this question:
ToList()-- Does it Create a New List?
By using ToList(), you can remove from your original list, because you're actually iterating over a copy.
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
If the function that determines which items to delete has no side effects and doesn't mutate the item (it's a pure function), a simple and efficient (linear time) solution is:
list.RemoveAll(condition);
If there are side effects, I'd use something like:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
This is still linear time, assuming the hash is good. But it has an increased memory use due to the hashset.
Finally if your list is only an IList<T> instead of a List<T> I suggest my answer to How can I do this special foreach iterator?. This will have linear runtime given typical implementations of IList<T>, compared with quadratic runtime of many other answers.
As any remove is taken on a condition you can use
list.RemoveAll(item => item.Value == someValue);
List<T> TheList = new List<T>();
TheList.FindAll(element => element.Satisfies(Condition)).ForEach(element => TheList.Remove(element));
You can't use foreach, but you could iterate forwards and manage your loop index variable when you remove an item, like so:
for (int i = 0; i < elements.Count; i++)
{
if (<condition>)
{
// Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
elements.RemoveAt(i--);
}
}
Note that in general all of these techniques rely on the behaviour of the collection being iterated. The technique shown here will work with the standard List(T). (It is quite possible to write your own collection class and iterator that does allow item removal during a foreach loop.)
For loops are a bad construct for this.
Using while
var numbers = new List<int>(Enumerable.Range(1, 3));
while (numbers.Count > 0)
{
numbers.RemoveAt(0);
}
But, if you absolutely must use for
var numbers = new List<int>(Enumerable.Range(1, 3));
for (; numbers.Count > 0;)
{
numbers.RemoveAt(0);
}
Or, this:
public static class Extensions
{
public static IList<T> Remove<T>(
this IList<T> numbers,
Func<T, bool> predicate)
{
numbers.ForEachBackwards(predicate, (n, index) => numbers.RemoveAt(index));
return numbers;
}
public static void ForEachBackwards<T>(
this IList<T> numbers,
Func<T, bool> predicate,
Action<T, int> action)
{
for (var i = numbers.Count - 1; i >= 0; i--)
{
if (predicate(numbers[i]))
{
action(numbers[i], i);
}
}
}
}
Usage:
var numbers = new List<int>(Enumerable.Range(1, 10)).Remove((n) => n > 5);
However, LINQ already has RemoveAll() to do this
var numbers = new List<int>(Enumerable.Range(1, 10));
numbers.RemoveAll((n) => n > 5);
Lastly, you are probably better off using LINQ's Where() to filter and create a new list instead of mutating the existing list. Immutability is usually good.
var numbers = new List<int>(Enumerable.Range(1, 10))
.Where((n) => n <= 5)
.ToList();
Using Remove or RemoveAt on a list while iterating over that list has intentionally been made difficult, because it is almost always the wrong thing to do. You might be able to get it working with some clever trick, but it would be extremely slow. Every time you call Remove it has to scan through the entire list to find the element you want to remove. Every time you call RemoveAt it has to move subsequent elements 1 position to the left. As such, any solution using Remove or RemoveAt, would require quadratic time, O(n²).
Use RemoveAll if you can. Otherwise, the following pattern will filter the list in-place in linear time, O(n).
// Create a list to be filtered
IList<int> elements = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
// Filter the list
int kept = 0;
for (int i = 0; i < elements.Count; i++) {
// Test whether this is an element that we want to keep.
if (elements[i] % 3 > 0) {
// Add it to the list of kept elements.
elements[kept] = elements[i];
kept++;
}
}
// Unfortunately IList has no Resize method. So instead we
// remove the last element of the list until: elements.Count == kept.
while (kept < elements.Count) elements.RemoveAt(elements.Count-1);
I would reassign the list from a LINQ query that filtered out the elements you didn't want to keep.
list = list.Where(item => ...).ToList();
Unless the list is very large there should be no significant performance problems in doing this.
The best way to remove items from a list while iterating over it is to use RemoveAll(). But the main concern written by people is that they have to do some complex things inside the loop and/or have complex compare cases.
The solution is to still use RemoveAll() but use this notation:
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
By assuming that predicate is a Boolean property of an element, that if it is true, then the element should be removed:
int i = 0;
while (i < list.Count())
{
if (list[i].predicate == true)
{
list.RemoveAt(i);
continue;
}
i++;
}
In C# one easy way is to mark the ones you wish to delete then create a new list to iterate over...
foreach(var item in list.ToList()){if(item.Delete) list.Remove(item);}
or even simpler use linq....
list.RemoveAll(p=>p.Delete);
but it is worth considering if other tasks or threads will have access to the same list at the same time you are busy removing, and maybe use a ConcurrentList instead.
I wish the "pattern" was something like this:
foreach( thing in thingpile )
{
if( /* condition#1 */ )
{
foreach.markfordeleting( thing );
}
elseif( /* condition#2 */ )
{
foreach.markforkeeping( thing );
}
}
foreachcompleted
{
// then the programmer's choices would be:
// delete everything that was marked for deleting
foreach.deletenow(thingpile);
// ...or... keep only things that were marked for keeping
foreach.keepnow(thingpile);
// ...or even... make a new list of the unmarked items
others = foreach.unmarked(thingpile);
}
This would align the code with the process that goes on in the programmer's brain.
foreach(var item in list.ToList())
{
if(item.Delete) list.Remove(item);
}
Simply create an entirely new list from the first one. I say "Easy" rather than "Right" as creating an entirely new list probably comes at a performance premium over the previous method (I haven't bothered with any benchmarking.) I generally prefer this pattern, it can also be useful in overcoming Linq-To-Entities limitations.
for(i = list.Count()-1;i>=0;i--)
{
item=list[i];
if (item.Delete) list.Remove(item);
}
This way cycles through the list backwards with a plain old For loop. Doing this forwards could be problematic if the size of the collection changes, but backwards should always be safe.
Just wanted to add my 2 cents to this in case this helps anyone, I had a similar problem but needed to remove multiple elements from an array list while it was being iterated over. the highest upvoted answer did it for me for the most part until I ran into errors and realized that the index was greater than the size of the array list in some instances because multiple elements were being removed but the index of the loop didn't keep track of that. I fixed this with a simple check:
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
There is an option that hasn't been mentioned here.
If you don't mind adding a bit of code somewhere in your project, you can add and extension to List to return an instance of a class that does iterate through the list in reverse.
You would use it like this :
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
And here is what the extension looks like:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
This is basically list.Reverse() without the allocation.
Like some have mentioned you still get the drawback of deleting elements one by one, and if your list is massively long some of the options here are better. But I think there is a world where someone would want the simplicity of list.Reverse(), without the memory overhead.
Copy the list you are iterating. Then remove from the copy and interate the original. Going backwards is confusing and doesn't work well when looping in parallel.
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
I would do like this
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
OUTPUT
Fred Jones
Billy TheKid
I found myself in a similar situation where I had to remove every nth element in a given List<T>.
for (int i = 0, j = 0, n = 3; i < list.Count; i++)
{
if ((j + 1) % n == 0) //Check current iteration is at the nth interval
{
list.RemoveAt(i);
j++; //This extra addition is necessary. Without it j will wrap
//down to zero, which will throw off our index.
}
j++; //This will always advance the j counter
}
The cost of removing an item from the list is proportional to the number of items following the one to be removed. In the case where the first half of the items qualify for removal, any approach which is based upon removing items individually will end up having to perform about N*N/4 item-copy operations, which can get very expensive if the list is large.
A faster approach is to scan through the list to find the first item to be removed (if any), and then from that point forward copy each item which should be retained to the spot where it belongs. Once this is done, if R items should be retained, the first R items in the list will be those R items, and all of the items requiring deletion will be at the end. If those items are deleted in reverse order, the system won't end up having to copy any of them, so if the list had N items of which R items, including all of the first F, were retained,
it will be necessary to copy R-F items, and shrink the list by one item N-R times. All linear time.
My approach is that I first create a list of indices, which should get deleted. Afterwards I loop over the indices and remove the items from the initial list. This looks like this:
var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
Trace the elements to be removed with a property, and remove them all after process.
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = false;
foreach (MyProperty currObj in _Group)
{
// here it is supposed that you decide the "remove conditions"...
cond = true; // set true or false...
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
myList.RemoveAt(i--);
simples;

Iterating through TableLayoutPanel to dispose controls - some controls get skipped [duplicate]

I am looking for a better pattern for working with a list of elements which each need processed and then depending on the outcome are removed from the list.
You can't use .Remove(element) inside a foreach (var element in X) (because it results in Collection was modified; enumeration operation may not execute. exception)... you also can't use for (int i = 0; i < elements.Count(); i++) and .RemoveAt(i) because it disrupts your current position in the collection relative to i.
Is there an elegant way to do this?
Iterate your list in reverse with a for loop:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
Example:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
Alternately, you can use the RemoveAll method with a predicate to test against:
safePendingList.RemoveAll(item => item.Value == someValue);
Here's a simplified example to demonstrate:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
foreach (var item in list.ToList()) {
list.Remove(item);
}
If you add ".ToList()" to your list (or the results of a LINQ query), you can remove "item" directly from "list" without the dreaded "Collection was modified; enumeration operation may not execute." error. The compiler makes a copy of "list", so that you can safely do the remove on the array.
While this pattern is not super efficient, it has a natural feel and is flexible enough for almost any situation. Such as when you want to save each "item" to a DB and remove it from the list only when the DB save succeeds.
A simple and straightforward solution:
Use a standard for-loop running backwards on your collection and RemoveAt(i) to remove elements.
Reverse iteration should be the first thing to come to mind when you want to remove elements from a Collection while iterating over it.
Luckily, there is a more elegant solution than writing a for loop which involves needless typing and can be error prone.
ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
foreach (int myInt in test.Reverse<int>())
{
if (myInt % 2 == 0)
{
test.Remove(myInt);
}
}
Using the ToArray() on a generic list allows you to do a Remove(item) on your generic List:
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
Select the elements you do want rather than trying to remove the elements you don't want. This is so much easier (and generally more efficient too) than removing elements.
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
I wanted to post this as a comment in response to the comment left by Michael Dillon below, but it's too long and probably useful to have in my answer anyway:
Personally, I'd never remove items one-by-one, if you do need removal, then call RemoveAll which takes a predicate and only rearranges the internal array once, whereas Remove does an Array.Copy operation for every element you remove. RemoveAll is vastly more efficient.
And when you're backwards iterating over a list, you already have the index of the element you want to remove, so it would be far more efficient to call RemoveAt, because Remove first does a traversal of the list to find the index of the element you're trying to remove, but you already know that index.
So all in all, I don't see any reason to ever call Remove in a for-loop. And ideally, if it is at all possible, use the above code to stream elements from the list as needed so no second data structure has to be created at all.
Using .ToList() will make a copy of your list, as explained in this question:
ToList()-- Does it Create a New List?
By using ToList(), you can remove from your original list, because you're actually iterating over a copy.
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
If the function that determines which items to delete has no side effects and doesn't mutate the item (it's a pure function), a simple and efficient (linear time) solution is:
list.RemoveAll(condition);
If there are side effects, I'd use something like:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
This is still linear time, assuming the hash is good. But it has an increased memory use due to the hashset.
Finally if your list is only an IList<T> instead of a List<T> I suggest my answer to How can I do this special foreach iterator?. This will have linear runtime given typical implementations of IList<T>, compared with quadratic runtime of many other answers.
As any remove is taken on a condition you can use
list.RemoveAll(item => item.Value == someValue);
List<T> TheList = new List<T>();
TheList.FindAll(element => element.Satisfies(Condition)).ForEach(element => TheList.Remove(element));
You can't use foreach, but you could iterate forwards and manage your loop index variable when you remove an item, like so:
for (int i = 0; i < elements.Count; i++)
{
if (<condition>)
{
// Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
elements.RemoveAt(i--);
}
}
Note that in general all of these techniques rely on the behaviour of the collection being iterated. The technique shown here will work with the standard List(T). (It is quite possible to write your own collection class and iterator that does allow item removal during a foreach loop.)
For loops are a bad construct for this.
Using while
var numbers = new List<int>(Enumerable.Range(1, 3));
while (numbers.Count > 0)
{
numbers.RemoveAt(0);
}
But, if you absolutely must use for
var numbers = new List<int>(Enumerable.Range(1, 3));
for (; numbers.Count > 0;)
{
numbers.RemoveAt(0);
}
Or, this:
public static class Extensions
{
public static IList<T> Remove<T>(
this IList<T> numbers,
Func<T, bool> predicate)
{
numbers.ForEachBackwards(predicate, (n, index) => numbers.RemoveAt(index));
return numbers;
}
public static void ForEachBackwards<T>(
this IList<T> numbers,
Func<T, bool> predicate,
Action<T, int> action)
{
for (var i = numbers.Count - 1; i >= 0; i--)
{
if (predicate(numbers[i]))
{
action(numbers[i], i);
}
}
}
}
Usage:
var numbers = new List<int>(Enumerable.Range(1, 10)).Remove((n) => n > 5);
However, LINQ already has RemoveAll() to do this
var numbers = new List<int>(Enumerable.Range(1, 10));
numbers.RemoveAll((n) => n > 5);
Lastly, you are probably better off using LINQ's Where() to filter and create a new list instead of mutating the existing list. Immutability is usually good.
var numbers = new List<int>(Enumerable.Range(1, 10))
.Where((n) => n <= 5)
.ToList();
Using Remove or RemoveAt on a list while iterating over that list has intentionally been made difficult, because it is almost always the wrong thing to do. You might be able to get it working with some clever trick, but it would be extremely slow. Every time you call Remove it has to scan through the entire list to find the element you want to remove. Every time you call RemoveAt it has to move subsequent elements 1 position to the left. As such, any solution using Remove or RemoveAt, would require quadratic time, O(n²).
Use RemoveAll if you can. Otherwise, the following pattern will filter the list in-place in linear time, O(n).
// Create a list to be filtered
IList<int> elements = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
// Filter the list
int kept = 0;
for (int i = 0; i < elements.Count; i++) {
// Test whether this is an element that we want to keep.
if (elements[i] % 3 > 0) {
// Add it to the list of kept elements.
elements[kept] = elements[i];
kept++;
}
}
// Unfortunately IList has no Resize method. So instead we
// remove the last element of the list until: elements.Count == kept.
while (kept < elements.Count) elements.RemoveAt(elements.Count-1);
I would reassign the list from a LINQ query that filtered out the elements you didn't want to keep.
list = list.Where(item => ...).ToList();
Unless the list is very large there should be no significant performance problems in doing this.
The best way to remove items from a list while iterating over it is to use RemoveAll(). But the main concern written by people is that they have to do some complex things inside the loop and/or have complex compare cases.
The solution is to still use RemoveAll() but use this notation:
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
By assuming that predicate is a Boolean property of an element, that if it is true, then the element should be removed:
int i = 0;
while (i < list.Count())
{
if (list[i].predicate == true)
{
list.RemoveAt(i);
continue;
}
i++;
}
In C# one easy way is to mark the ones you wish to delete then create a new list to iterate over...
foreach(var item in list.ToList()){if(item.Delete) list.Remove(item);}
or even simpler use linq....
list.RemoveAll(p=>p.Delete);
but it is worth considering if other tasks or threads will have access to the same list at the same time you are busy removing, and maybe use a ConcurrentList instead.
I wish the "pattern" was something like this:
foreach( thing in thingpile )
{
if( /* condition#1 */ )
{
foreach.markfordeleting( thing );
}
elseif( /* condition#2 */ )
{
foreach.markforkeeping( thing );
}
}
foreachcompleted
{
// then the programmer's choices would be:
// delete everything that was marked for deleting
foreach.deletenow(thingpile);
// ...or... keep only things that were marked for keeping
foreach.keepnow(thingpile);
// ...or even... make a new list of the unmarked items
others = foreach.unmarked(thingpile);
}
This would align the code with the process that goes on in the programmer's brain.
foreach(var item in list.ToList())
{
if(item.Delete) list.Remove(item);
}
Simply create an entirely new list from the first one. I say "Easy" rather than "Right" as creating an entirely new list probably comes at a performance premium over the previous method (I haven't bothered with any benchmarking.) I generally prefer this pattern, it can also be useful in overcoming Linq-To-Entities limitations.
for(i = list.Count()-1;i>=0;i--)
{
item=list[i];
if (item.Delete) list.Remove(item);
}
This way cycles through the list backwards with a plain old For loop. Doing this forwards could be problematic if the size of the collection changes, but backwards should always be safe.
Just wanted to add my 2 cents to this in case this helps anyone, I had a similar problem but needed to remove multiple elements from an array list while it was being iterated over. the highest upvoted answer did it for me for the most part until I ran into errors and realized that the index was greater than the size of the array list in some instances because multiple elements were being removed but the index of the loop didn't keep track of that. I fixed this with a simple check:
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
There is an option that hasn't been mentioned here.
If you don't mind adding a bit of code somewhere in your project, you can add and extension to List to return an instance of a class that does iterate through the list in reverse.
You would use it like this :
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
And here is what the extension looks like:
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}
This is basically list.Reverse() without the allocation.
Like some have mentioned you still get the drawback of deleting elements one by one, and if your list is massively long some of the options here are better. But I think there is a world where someone would want the simplicity of list.Reverse(), without the memory overhead.
Copy the list you are iterating. Then remove from the copy and interate the original. Going backwards is confusing and doesn't work well when looping in parallel.
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
I would do like this
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
OUTPUT
Fred Jones
Billy TheKid
I found myself in a similar situation where I had to remove every nth element in a given List<T>.
for (int i = 0, j = 0, n = 3; i < list.Count; i++)
{
if ((j + 1) % n == 0) //Check current iteration is at the nth interval
{
list.RemoveAt(i);
j++; //This extra addition is necessary. Without it j will wrap
//down to zero, which will throw off our index.
}
j++; //This will always advance the j counter
}
The cost of removing an item from the list is proportional to the number of items following the one to be removed. In the case where the first half of the items qualify for removal, any approach which is based upon removing items individually will end up having to perform about N*N/4 item-copy operations, which can get very expensive if the list is large.
A faster approach is to scan through the list to find the first item to be removed (if any), and then from that point forward copy each item which should be retained to the spot where it belongs. Once this is done, if R items should be retained, the first R items in the list will be those R items, and all of the items requiring deletion will be at the end. If those items are deleted in reverse order, the system won't end up having to copy any of them, so if the list had N items of which R items, including all of the first F, were retained,
it will be necessary to copy R-F items, and shrink the list by one item N-R times. All linear time.
My approach is that I first create a list of indices, which should get deleted. Afterwards I loop over the indices and remove the items from the initial list. This looks like this:
var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
Trace the elements to be removed with a property, and remove them all after process.
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = false;
foreach (MyProperty currObj in _Group)
{
// here it is supposed that you decide the "remove conditions"...
cond = true; // set true or false...
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
myList.RemoveAt(i--);
simples;

Help with converting foreach loop to while loop in c#

I had learnt by reading your great answers here, that it is not good practice deleting items from within a foreach loop, as it is (and I quote) "Sawing off the branch you're sitting on".
My code currently removes the text from the dropdownlist, but the actual item remains (just without text displayed).
In other words, it isn't deleting, and probably can't because you can't delete from within a foreach loop.
After hours of trying I am unable to get my head around a way of doing it.
//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
//this is the foreach loop
foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
{
//This rules out seperators
if (mItem is ToolStripMenuItem)
{
ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;
//This matches the dropdownitems text to the CheckedItems String
if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
{
//And deletes the item
menuItem.DropDownItems.Remove(mItem);
}
}
}
}
But it isn't deleting because it is within a foreach loop!
I would greatly appreciate your help, and be truly amazed if anyone can get their head around this code :)
Kind Regards
Fun with LINQ!
// Loop through the checked items, same as you did.
foreach (var checkedItem in this.organizeFav.CheckedItems)
{
// Cast from IEnumerable to IEnumerable<T> so we can abuse LINQ
var matches = favoritesToolStripMenuItem.DropDownItems.Cast<ToolStripItem>()
// Only items that the Text match
.Where(item => item.Text == checkedItem.Text)
// Don't match separators
.Where(item => item is ToolStripMenuItem)
// Select the keys for the later .Remove call
.Select(item => item.Name);
// Loop through all matches
foreach (var key in matches)
{
// Remove them with the Remove(string key) overload.
favoritesToolStripMenuItem.Remove(key);
}
}
You don't need a foreach loop - just use a regular loop but go in reverse, start at the end and go to the beginning.
//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
//this *replaces* the foreach loop
for(int j = favoritesToolStripMenuItem.DropDownItems.Count - 1; j >= 0; j--)
{
ToolStripMenuItem menuItem = favoritesToolStripMenuItem.DropDownItems[j] as ToolStripMenuItem;
//This rules out seperators
if (menuItem != null)
{
//This matches the dropdownitems text to the CheckedItems String
if (menuItem.Text.ToString() == organizeFav.CheckedItems[i].ToString())
{
favoritesToolStripMenuItem.DropDownItems.Remove(menuItem);
}
}
}
}
this was #Kurresmack's code rearranged, i just coded it directly here in the page so excuse any small syntax error or anything obvious i overlooked (disclaimer: it is a sample!!)
You can still treat favoritesToolStripMenuItem.DropDownItems as a collection like you were, but you don't have to enumerate over it using a foreach. This cuts down on a few lines of code, and it works because you are iterating it in reverse order, you will not get an index out of bounds exception.
Try something like this:
//For each checked box, run the delete code
for (int i = 0; i < this.organizeFav.CheckedItems.Count; i++)
{
List<ToolStripItem> toRemove = new List<ToolStripItem>();
//this is the foreach loop
foreach (ToolStripItem mItem in favoritesToolStripMenuItem.DropDownItems)
{
//This rules out seperators
if (mItem is ToolStripMenuItem)
{
ToolStripMenuItem menuItem = mItem as ToolStripMenuItem;
//This matches the dropdownitems text to the CheckedItems String
if (((ToolStripMenuItem)mItem).Text.ToString() == organizeFav.CheckedItems[i].ToString())
{
toRemove.Add(mItem);
}
}
}
foreach(var item in toRemove)
{
favoritesToolStripMenuItem.DropDownItems.Remove(item);
}
}
To my mind, the way to make the code work is:
1. Create an instance of the type the favoritesToolStripMenuItem.DropDownItems collection is.
2. In the foreach loop, add all items, you do not want to be removed, to that collection.
3. Make favoritesToolStripMenuItem.DropDownItems to point to the new collection. Or clear favoritesToolStripMenuItem.DropDownItems and load the items from the new collection to it.
Hope this helps
Instead of a foreach use a reverse for-Loop:
for(int reverseIndex = myList.Count - 1; reverseIndex >= 0; reverseIndex--)
{
var currentItem = myList[reverseIndex];
if(MatchMyCondition(currentItem))
{
myList.Remove(currentItem);
}
}

how to use hash table to avoid duplicate entries in a listview when items are added to it?

what is the way to avoid the redundancy in the listview when the items are added to it..
im using winforms c#.net..
i mean how can i compare between the items in listview1 and items in listview2 so that while adding the items from one listview to another it could not enter the items that are already entered in the target listview..
im able to add items from one listview to other but it is adding auplicate items also what is the way to get rid of it..???
You can think of something like:
Hashtable openWith = new Hashtable();
// Add some elements to the hash table. There are no
// duplicate keys, but some of the values are duplicates.
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
// The Add method throws an exception if the new key is
// already in the hash table.
try
{
openWith.Add("txt", "winword.exe");
}
catch
{
Console.WriteLine("An element with Key = \"txt\" already exists.");
}
// ContainsKey can be used to test keys before inserting
// them.
if (!openWith.ContainsKey("ht"))
{
openWith.Add("ht", "hypertrm.exe");
Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]);
}
Now to meet the changes in the problem after edit, you can do it like this:
if(!ListView2.Items.Contains(myListItem))
{
ListView2.Items.Add(myListItem);
}
You can also refer a similar problem in How to copy the selected items from one listview to another on button click in c#net?
As suggested, hash table is a good way to deter such redundancy.
A dictonary ... Any array.. a list all possible, just loop threw the items/subitems, add them to the "array" then loop threw the array to check it against the otehr list...
Here is a example i use to remove dups on a buttonclick, but you can easily change to the code to suit your needs.
I used the below to remove "Dups" in a listview on a button click, i am searching subitem you can edit code for your own use...
uses dictionary and a little easy "update" class i wrote.
private void removeDupBtn_Click(object sender, EventArgs e)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
int num = 0;
while (num <= listView1.Items.Count)
{
if (num == listView1.Items.Count)
{
break;
}
if (dict.ContainsKey(listView1.Items[num].SubItems[1].Text).Equals(false))
{
dict.Add(listView1.Items[num].SubItems[1].Text, ListView1.Items[num].SubItems[0].Text);
}
num++;
}
updateList(dict, listView1);
}
and using a little updateList() class...
private void updateList(Dictionary<string, string> dict, ListView list)
{
#region Sort
list.Items.Clear();
string[] arrays = dict.Keys.ToArray();
int num = 0;
while (num <= dict.Count)
{
if (num == dict.Count)
{
break;
}
ListViewItem lvi;
ListViewItem.ListViewSubItem lvsi;
lvi = new ListViewItem();
lvi.Text = dict[arrays[num]].ToString();
lvi.ImageIndex = 0;
lvi.Tag = dict[arrays[num]].ToString();
lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = arrays[num];
lvi.SubItems.Add(lvsi);
list.Items.Add(lvi);
list.EndUpdate();
num++;
}
#endregion
}
Good luck!

Categories