For Each - Inverted Order - c#

I have a List<Object>. I want to iterate over this list, but I want the order to be inverted, so when I use the object, it will start from the last to the first. How can I do it, minimal code?
Thanks.
P.S. I'm using C#, WinForms.

Use the extension method Enumerable<T>.Reverse. This will iterate through the list in a reverse order and leave the original list intact.
foreach(var item in list.AsEnumerable().Reverse())
{
}
Reverse , however, traverses the list and caches your items in a reverse order when iteration starts. In 90% of the cases this is fine, because it's still a O(n) operation, but if you want to avoid this cache just use a plain old for
for(int i = list.Count - 1; i >= 0; i--) { }

Related

What element does ConcurrentDictionary.ElementAt return

In my code I got an ConcurrentDictionary now I want to iterate over each element in the Dictionary, but if a condition is true I want to remove an element from this Dictionary so I can't use a foreach loop. Also it might happen that the Dictionary will get a new element while in the loop or get one removed from a different thread. After some research I ended up using ElementAt.
Now my question is if the ConcurrentDictionary will release the indexes again like a List does. So that the first element will always have the index 0.
This is what my code looks like, CommandHandler.Timeouter is from ConcurrentDictionary:
int current = 0;
while (CommandHandler.Timeouter.Count() > current)
{
var info = CommandHandler.Timeouter.ElementAt(current);
var timeoutcooldown = info.Value.LastCommandTime.AddMinutes(1);
if (timeoutcooldown < DateTime.UtcNow)
{
CommandHandler.Timeouter.TryRemove(info.Key, out _);
}
else current++;
}
ElementAt just treats the dictionary as an IEnumerable<KeyValuePair<TKey, TValue>>. Dictionaries are not ordered. The index is therefore meaningless. Think of the elements coming back in random order each time. Also, ElementAt has no way to make this thread safe.
It seems you want to implement cache expiration. Consider just using lock to access a normal dictionary. If there is not much contention this will be the simplest solution and very fast.
An alternative code pattern to this loop would be this:
var itemsToExpire = myDict.Where(/* compute expiration */).ToList();
foreach (var item in itemsToExpire)
myDict.Remove(item);
No need for any complicated looping.

Compare and "Equalize" Collections

Let's suppose we have a List collection A and an int array B. Now we need to see, independent of order, which elements from the array B are present in collection A. Add the elements that are missing and delete the elements that are not to be found int array B.
I have done this using the code below :
for (int i = 0; i < A.Count; i++)
{
for (int k = 0; k < B.Length; k++)
{
if (A[i] == B[k]) goto Found;
}
A.RemoveAt(i);
Found: continue;
}
for (int i = 0; i < B.Length; i++)
{
for (int k = 0; k < A.Count; k++)
{
if (A[k] == B[i]) goto Found;
}
A.Add(B[i]);
Found: continue;
}
Is there a faster way to achieve the same result? Notice that I cannot just delete A and create a new one in accordance with B because this is just a simplified example.
It's futile, in the end you will get collection B all over again. just create collection A based on array B. simple as that!
The very short (and fairly fast) version would be
A.Clear();
A.AddRange(B);
but perhaps you don't really want that either. You can shorten your code a bit when using the Contains method, though:
for (int i = A.Count; i >= 0; i--) {
if (!B.Contains(A[i])) {
A.RemoveAt(i);
}
}
foreach (var item in B) {
if (!A.Contains(item)) {
A.Add(item);
}
}
The first loop cannot be a foreach loop because A is modified while it is being iterated over. It also runs backwards to ensure that every item is looked at.
However, this has quadratic runtime (more precisely: O(|A| · |B|)) and can get slow rather quickly (pun not intended) with large lists. For better runtime (albeit higher memory requirements) you may need to use HashSets for the Contains tests requiring only O(|A| + |B|) runtime performance at the cost of O(|A| + |B|) more memory.
This is a quite long-winded way of getting to the point, though: If you don't care about order of your items, then it seems like your lists are more like sets. In that case, a set data structure makes more sense because it can do those operations efficiently. And you apparently don't care about element order, because you're just adding missing items at the end anyway.
I think using LINQ should be fast:
A.RemoveAll(tmp => !B.Contains(tmp));
A.AddRange(B.Where(tmp => !A.Contains(tmp)));
EDIT: as pointed out by Joey this is still only O(|A| · |B|).
OK I will give you some more details. The example I set above was oversimplified. What I actually have is an XML file which is loaded on an XElement. There are child nodes with specific attributes mapping precisely to the properties of a custom type in my application. Every child node creates an instance of the aforementioned type.
For purposes of extensibility, if I need to add a new property to the custom type, I want all records in the XML file to be updated with the new attribute with an empty value. And if I delete a property, I want the opposite. So here, I must check the collection of Attributes towards the PropertyInfo[] of the custom type. I cannot delete all of the Attributes and recreate them again because their values will be lost as well.
In my approach, I could see that some checks were done twice and because I am really novice, I thought that maybe this was a casual issue that is dealt with a way I could not think of. Thank you all for the nice replys.

Does list.count physically iterate through the list to count it, or does it keep a pointer

I am stepping through a large list of object to do some stuff regarding said objects in the list.
During my iteration, I will remove some objects from the list depending on certain criteria.
Once all is done, I need to update the UI regarding the number of objects in my list. (List of T).
QUESTION:
When I call list.count, does .net actually iterate through the list to
count it, or does it store the count as a property/variable?
If .net physically re-iterates through the list, I may just as well keep a counter on my own iteration through the list, and save the overhead?
Thanks
It simply keeps an internal int to track the number of items. So no iteration.
The documentation says retrieving Count is an O(1) operation:
http://msdn.microsoft.com/en-us/library/27b47ht3%28v=vs.110%29.aspx
You can see for yourself:
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
List is implemented as an array list, and it keeps track of its own size, so invoking the .Count property doesn't require any iteration.
If you call the LINQ .Count() extension method, this will check whether the underlying IEnumerable<> implements ICollection (which a List<> does), and use the .Count property on that interface if possible. So this won't cause any iteration to occur either.
Incidentally, there are other problems you're going to encounter if you attempt to remove items from your list while iterating through it. It's not really clear how iteration should behave when you are removing elements out from under the iterator, so List<>s will avoid this issue entirely by throwing an exception if the list has been modified since its enumerator was created.
You can use a decompiler, such as the freely-available ILSpy, to answer these questions. If you're referring to the List<T> type, then the Count getter simply involves reading a field:
public int Count
{
get { return this._size; }
}
As stated here under the remarks tab
http://msdn.microsoft.com/en-us/library/27b47ht3(v=vs.110).aspx
Retrieving the value of this property is an O(1) operation.
Which means no iteration is occurring.
You tagged your question with both vb.net and c#, so in reply to "If .net physically re-iterates through the list, I may just as well keep a counter on my own iteration through the list, and save the overhead?"
If your iteration is with a For i = first To last then VB.NET will evaluate first and last when it enters the loop:
Dim first As Integer = 1
Dim last As Integer = 3
For i = first To last
Console.Write(i.ToString() & " ")
last = -99
Next
outputs: 1 2 3
If you do the equivalent in C#, first and last are evaluated on every iteration:
int first = 1;
int last = 1;
for (int i = first; i <= last; i++)
{
Console.Write(i.ToString() + " ");
last = -99;
}
outputs: 1
If your .Count() function/property is expensive to evaluate and/or you don't want it to be re-evaluated on each iteration (for some other reason), then in C# you could assign it to a temporary variable.

how properly remove item from list [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Exception during iteration on collection and remove items from that collection
How to remove elements from a generic list while iterating around it?
Better way to remove matched items from a list
// tmpClientList is List<Client> type
if (txtboxClientName.Text != "")
foreach (Client cli in tmpClientList)
if (cli.Name != txtboxClientName.Text)
tmpClientList.Remove(cli);
Error: "Collection was modified; enumeration operation may not execute."
How can i remove items from the list, in some simple way, without saving indexes of these items in another list or array, and removing them in another place in the code. Tried also RemoveAt(index) but it's exactly the same situation, modifying when loop runs.
Move backwards through the list.. that way removing an item does not affect the next item.
for(var i=tmpClientList.Count-1;i>=0;i--)
{
if (tmpClientList[i].Name != txtboxClientName.Text)
tmpClientList.RemoveAt(i);
}
On a List<T>, there is a RemoveAll method that takes a delegate to indicate whether to remove the item. You can use it like this:
tmpCLientList.RemoveAll(cli => cli.Name != txtboxClientName.Text);
Either use a for/while loop, or tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text). As you didn't specify which c# version you are using, ymmw.
Don't use foreach. Use for and descend the list (i.e. start from the end), using RemoveAt.
So,
// tmpClientList is List<Client> type
if (txtboxClientName.Text != "")
foreach (int pos = tmpClientList.Length - 1; pos >= 0; pos--)
{
Client cli = tmpClientList[pos];
if (cli.Name != txtboxClientName.Text)
tmpClientList.RemoveAt(pos);
}
The problem is that you are trying the modify the list in a foreach iteration. Replace that with a for and you should be ok.
Also, since you seem to be using user input for the name, consider cleaning up the input a bit, at least with a Trim() to remove extra white spaces. If you don't, 'John ' and 'John' will be two different things.
Same for the initial != "" check.
You can create another list with the items you want to delete and iterate the new list to remove items from your "txtboxClientName" list.
Actually, foreach uses Enumerators to iterate through given Item-Collections. Going further the System.Collections.Generic.List<T> implements the IEnumarable-Interface to provide a Class, that knows how to iterate through the items of the list, i.e. the Enumerator. Now if you iterate through that list by using foreach the Enumerator keeps track of the current position, how to reach the next position and some other stuff. The internal logic could be something like storing the number of items in a variable n and then access all objects from 0 to n-1. As you may notice if any object is removed between the iteration steps we shall end in a NullReferenceException when the Enumerator tries to deliver the last object of the list. So to prevent any iteration failures, the list itself is not allowed to be modified during Enumeration.
Hope I was able to state that out at least a little bit comprehensively. :-)

How to shift items in an array?

I have an array of items that are time sensitive. After an amount of time, the last item needs to fall off and a new item is put at the beginning.
What is the best way to do this?
I would suggest using a queue, just a special instance of an array or list. When your timed event occurs, pop the last item from the queue, and then push your new item on.
Probably the easiest way to do this with an array is to use a circular index. Rather than always looking at array[n], you would reference array[cIndex] (where cIndex referrs to the item in the array being indexed (cIndex is incremented based on the arraySize (cIndex % arraySize)).
When you choose to drop the oldest item in the array, you would simply reference the element located at ((cIndex + (arraySize - 1)) % arraySize).
Alternatively, you could use a linkedList approach.
Use a Queue instead.
By using a Queue, preferably one implemented using a linked-list.
Have a look at using a Queue rather than a simple array.
A queue would work if there a fixed number of items.
Given that the 'amount of time' is known, how about a SortedDictionary with a DateTime key and override the Add method to remove all items with keys that are too old.
LinkedList<T> has AddFirst and RemoveLast members that should work perfectly.
EDIT: Looking at the Queue docs, it seems they use an internal array. As long as the implementation uses a circular-array type algorithm performance should be fine.
In csharp 3 you can do:
original = new[] { newItem }.Concat(
original.Take(original.Count() - 1)).ToArray()
But you are probably better off using a specialised datastructure
Queue is great for FIFO arrays. For generic array handling, use List(T)'s
Insert(0, x) and RemoveAt(0) methods to put or remove items in front of the list, for example.
Technically you need a deque. A queue has items pushed and popped off one end only. A deque is open at both ends.
Most languages will allow array manipulation, just remove the first element and put another one on the end.
Alternatively you can shift every element, by looping. Just replace each element (starting from the oldest) with its neighbour. Then place the new item in the last element.
If you know that your deque won't go above a certain size, then you can make it circular. You'll need two pointers to tell you where the two ends are though. Adding and removing items, will increase/decrease your pointers accordingly. You'll have to detect a buffer overflow condition (i.e. your pointers 'cross'). And you'll have to use modular arithmetic so your pointers go in a circle around the array.
Or you could time stamp each element in the array and remove them when they become too 'old'. You can either do this by keeping a separate array indexed in the same way, or by having an array of two element arrays, with the time stamp stored in one of the sub-elements.
If you're looking for the fastest way of doing this, it's going to be a circular array: you keep track of your current position in the array (ndx), and the end of the array (end), so when you insert an item, you implicitly eliminate the oldest item.
A circular array is the fastest implementation of a fixed-size queue that I know of.
For example, in C/C++ it would look like this for ints (quitting when you get a 0):
int queue[SIZE];
int ndx=0; // start at the beginning of the array
int end=SIZE-1;
int newitem;
while(1){
cin >> newitem;
if(!newitem) // quit if it's a 0
break;
if(ndx>end) // need to loop around the end of the array
ndx=0;
queue[ndx] = newitem;
ndx++
}
Lots of optimization could be done, but if you want to built it yourself, this is the fastest route.
If you don't care about performance, use a shipped Queue object because it should be generalized.
It may or may not be optimized, and it may not support a fixed size list, so be sure to check the documentation on it before using.

Categories