I have the following collection where I enter some values using a method:
Collection<double> temp = new Collection<double>();
I would like to remove all the items from the collection at some point so I could be able to start filling it again from the beginning as I do the first time I initialize the program.
I tried like this but it doesn't work.
for (int i = 0; i < temp.Count; i++)
{
temp.RemoveAt(i);
}
What is wrong?
Thanks for your help!
Use the Clear method:
temp.Clear();
The reason why your loop doesn't work is because when you do a RemoveAt, the indexes of all items shift. So, say you started with this:
6, 2, 8, 5, 3
In the first iteration, i is 0, and the first item will be removed:
2, 8, 5, 3
For the second iteration, i is 1, but that's no-longer the next item to delete, so you get this:
2, 5, 3
Then, i is 2, and you get this:
2, 5
Now i is > temp.Count. See how you can be left with leftover items?
You can use Clear() method -
temp.Clear();
By calling RemoveAt, you are assuming there does exist an item at the given index. However, by removing it, the collection has one less item, and hence your for loop doesn't make sense. It won't throw an exception just because of temp.Count being evaluated during each iteration. In effect, it will remove only every other item from the collection.
Instead, use the Clear method.
You can't use indexed removal, as soon as you remove the first item, the collection gets reindexed, the second element becomes first, third becomes second etc. You will remove every odd element and get and exception after going out of the collection size. In .net implementation you would probably get an exception eariler, as soon as you remove the first item, the enumerator will complain that you can't modify the collection you are enumerating at the very moment.
There are few ways to work this around, the easiest it to clear the collection using dedicated method (Clear). In case of collection of references, you could also create a collection of copies of references from the original collection and iterate over the cloned collection but remove from the original.
If you really need to remove one element at a time (rather than calling Clear() to remove them all in one go) then you need to iterate in reverse order:
int count = temp.Count;
for (int i = count-1; i >= 0; i--)
{
temp.RemoveAt(i);
}
This will remove the elements from the end of the list so that your index is always within range of the remaining list and you remove all the items from the list.
Or only use the size as a counter:
int count = temp.Count;
for (int i = 0; i < count ; i++)
{
temp.RemoveAt(0);
}
This isn't using the collections iterators at all and as you're getting the count before you start removing elements it shouldn't fail.
Something like this would only be needed if you needed to do some processing on each element etc. before removing it from the list.
Related
Say I have an ObservableCollection with two items:
0: dateUnix: 333
1: dateUnix: 222
Now I want to add a new Item:
dateUnix: 300
If I just were to use the .add() method, the item would get added at the end. But I want the item to be inserted between 222 and 300 since this would make the list sorted.
How do I insert an item at a certain position where it is less then item value after and higher then item value before?
Of the top, I can think of two ways of doing this.
One would be, as was pointed out in the comments, to just insert and sort afterwards.
Another, more complex and more rewarding way would be to find the index of the first item greater or lesser than the one you're inserting and insert it at that index. Your list seems to be sorted in descending order, so it'd need to be the first lesser than.
You could achieve this using LINQ:
ObservableCollection<Int> collection = new ObservableCollection(new List<int>{333,222}); // == [333,222]
Int toInsert = 300;
collection.Insert(collection.IndexOf(collection.First(elem => elem < toInsert)), toInsert); // output == [333,300,222]
See this Fiddle for a working example.
If your collection is already sorted, just find the appropriate index to insert the element at (either via a linear or the faster binary search) and use Insert to store the element at that specific index.
How do I remove the last two rows from a List.
At present, I am removing the 2 rows manually as shown below. However, there might be an instance where I have to define the number of rows to be removed as n. So, it will remove n number of rows from the bottom of the list. How can I make this change?
rows.RemoveAt(rows.Count - 1);
rows.RemoveAt(rows.Count - 2);
You could use RemoveRange:
rows.RemoveRange(rows.Count - n, n);
You could use LINQ:
rows = rows.Take(rows.Count - n).ToList();
As Spender said, there is a potential issue in your code. I call this a "Index Race Condition". After you remove the last element, something else becomes the new last Element. It is something you have to look out for with Indexed Collections. Keyd collections do not suffer from it.
In addition to what others said regarding using "RemoveRange" (if availible) or LINQ, there is also a chance you got the wrong collection type.
The Queue[T] and the Stack[T] are specialized collections for first-in, first-out and first-in, last-out cases respectively.
Here is my code:
int k = panel.Controls.OfType<DataGridView>().Count<DataGridView>();
foreach (Control control in panel.Controls.OfType<DataGridView>())
{
panel.Controls.Remove(control);
}
I have 4 DataGridView objects on panel that are created at runtime with the names 0, 1, 2, and 3, and "k" its shown correct value(4). But my foreach loop's first step is "0", second is "2", and then the loop ends. It skips two object and I don't know why.
If I put a second and third foreach statement, the result is correct.
Why is that so?
In the first loop your Control is Zero.
You remove the control.
Your next loop gets the next Control. Since its already returned the first control, it now returns the second Control, but since you've removed the Zero control the second Control is now 2.
The key to understanding this behaviour is that the OfType() returns an iterator, not a list. If you returned OfType().ToList() you would get a concrete list that would not be changed when you alter the list you derived it from.
So;
IList<object> x = underlyingList.OfType<object>() returns an iterator.
List<object> y = underlyingList.OfType<object>().ToList() returns a concrete list.
When you delete objects in the list you're iterating over you also alter its length.
First iteration you're at index 0 and length 4.
Second iteration is at index 1 (originally this item was index 2) and length 3.
Then your loop will terminate because you're at index 2 but there's no element at that index anymore because the ones who were there are now at index 0 and 1.
If you want to remove all elements this way you can iterate over the list backwards instead, this way you won't offset the list and making you miss the elements.
What is the most efficient method for getting the 10th item form the end of a list
I was thinking something like:
List[List.Count() - 10];
If you're using List<T> from System.Collections.Generic then you're not actually using singly linked list. It's backed by an array, and you can simple access it by index, as you already suggested:
list[list.Count - 10];
it will be O(1) operation. You should probably check if list has at least 10 elements before doing it so you don't get an exception.
However, if you have your own singly linked list structure you'll have to iterate the entire list to get Nth item from the end of the list. You can use the same approach, but that will force two round trips over the collection - first to get total number of elements and second to get Nth last element.
You can make it happen with just one iteration, if you store last N items you've seen, e.g. in a queue. This will be O(n) operation.
I tried many times to resolve this case but I always get an error because it's an Image in an ImageList. What code do I need to literally re-add the removed Image from the list. This is my code (The final line doesn't work).
int index9 = random.Next(0, normalCards1.Count - 1);
pictureBox9.Image = normalCards1[index9];
normalCards1.RemoveAt(index9);
...
normalCards1.Insert(index9);
you need to pass T item as well with index.
you can add it back this way:
normalCards1.Insert(index9,pictureBox9.Image);
See List.Insert Method MSDN docs here
ImageListCollection which is the type of ImageList.Images does not provide a way to insert items by index.
If you want to shuffle or somehow else reorder images you need to remove them all and add them again after reordering. I.e. adding all images to a List<T>, sort, and use AddRange.
You can also try using indexed access (imageList.Images[3] = ... ) to swap items.