Some time ago I read that foreach works with "copies" of objects and thus it can be used for information retrieval instead of its updating. I do not get it as it is entirely possible to loop through list of classes and change its field. Thanks!
What you may have read is that you can't modify a collection while iterating over it using foreach whereas you can (if you're careful) using a for loop. For example:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
var list = new List<int> { 1, 4, 5, 6, 9, 10 };
/* This version fails with an InvalidOperationException
foreach (int x in list)
{
if (x < 5)
{
list.Add(100);
}
Console.WriteLine(x);
}
*/
// This version is okay
for (int i = 0; i < list.Count; i++)
{
int x = list[i];
if (x < 5)
{
list.Add(100);
}
Console.WriteLine(x);
}
}
}
If that's not what you were referring to, please give more details - it's hard to explain what you've read without knowing exactly what it said.
You cannot modify the element in a foreach:
var list = new List<string>();
list.AddRange(new string[] { "A", "B", "C" });
foreach (var i in list)
{
// compilation error: Cannot assign 'i' because it is a 'foreach iteration variable'
i = "X";
}
Although when working with for you are accessing the element on the list with its index, and not the iterator, so this way you can modify the collection.
foreach use an Iterator to get each element of a sequence. The sequence can be Anything that implements IEnumerable. The IEnumerable does not need to be finite (the sequence 0 1 2 3 4... 1000... ) is IEnumerable.
for is only a C# constructs which allow you to declare a loop (used to do all sort of things, not only iterating through collections)
It's worth noting that the Iterator implementation in .NET for the collections does not support sequence modification during iteration.
foreach is using IEnumerable to loop through collection. This makes it impossible to modify this collection(remove, add items), but you still can modify objects inside, if they are reference types.
for is simple combination of simple loop combined with direct access to items in collection. There is no kind of blocking while this loop is going.
Compare it with a readonly field:
private readonly List<int> MyList = new List<int>();
Now, in this code I cannot do MyList = new List<int>() as that will alter what MyList points to, but I can alter the list pointed to with MyList.Add(3).
Likewise, you cannot alter the variable used by the foreach iteration, but can what it refers to:
foreach(List<int> lst in MyListOfLists)
{
lst = new List<int>(); // not allowed
lst.Add(3); // allowed
}
Finally, the enumerator used to implement foreach is not required to remain valid if the underlying collection is being used:
foreach(int x in SomeEnumerable)
{
if(x != 0)
SomeEnumerable.Add(0);
}
Assuming that Add modifies SomeEnumerable then the above might work, it might "work" in a strange and hard to understand way and it might throw an exception. No behaviour is guaranteed with such code and modifying a collection during enumeration is considered incorrect for this reason.
Related
I'm trying to obtain the last 10 objects within an arraylist.
Case: Arraylist full of objects[ChartObjectsInt] and [ChartObjectsReal] with indexes from 0-N, i want to obtain the last 10 persons (N-10), and with these last 10 objects I want to call functions from that object; like ChartObjectsInt.getLabelName();
Can anyone help?
Code I've reached so far:
private void getLastTenObjects()
{
foreach (ChartObjectsInt chartRecords in arraylistMonitor)
{
for (int i = 0; i < 10; i++)
{
arraylistMonitor.IndexOf(i);
}
}
}
Why don't you use List rather than ArrayList, if you do so it will be more easy to get last 10 element from list.
example:
var lastTenProducts = products.OrderByDescending(p => p.ProductDate).Take(10);
//here products is the List
If you don't want to use LINQ at all
for (var i = Math.Max(arraylistMonitor.Count - 10, 0); i < arraylistMonitor.Count; i++)
{
YourFunctionCallHere(arraylistMonitor[i]);
}
The above code will loop through the last 10 items of the ArrayList by setting i to the appropriate starting index - the Math.Max call there is in case the ArrayList has 9 or fewer elements in it.
If you are willing to use LINQ
var last10 = arraylistMonitor.Cast<object>().Reverse().Take(10);
will do what you want. You may also wish to add ToList after Take(10), depending on how you wish to consume last10.
Firstly it casts it to an IEnumerable<object> then goes through the IEnumerable backwards until it has (up to) 10 items.
If you specifically want last10 to be an ArrayList (which I wouldn't recommend) then use:
var last10 = new ArrayList(arraylistMonitor.Cast<object>().Reverse().Take(10).ToList());
As others have already said, I would use List<T> as ArrayList is effectively deprecated for that as it exists from a time when C# didn't have generics.
With that said, you could write a function that would work for a list of any size and take however many like so
public List<T> GetLastX<T>(List<T> list, int amountToTake)
{
return list.Skip(list.Count - amountToTake).ToList();
}
I have made a method that eliminates any replicates of the same string in a List.
now, the problem is that it gives me this error:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
I read in the internet, and i think that the problem is the i am removing an object from the list inside the foreach loop of the list.
foreach (string r in list)
{
int numberOfAppearance=0;
foreach (string rs in list)
{
if (r == rs && numberOfAppearance> 0)
list.Remove(rs);
else
numberOfAppearance++;
}
}
How can i fix the method? Thanks for the help
Firstly, as noted in comments, LINQ has got you covered here:
list = list.Distinct().ToList();
It's well worth looking into LINQ for data operations - it can make things much simpler.
As for what's wrong with your current code - there are a couple of things:
Firstly, you're removing by item rather than by index, which will remove the first occurrence of that item, not the one you're actually looking at
Secondly, if you modify a list while you're iterating over it, you will get precisely the exception you've seen. From the docs for List<T>.GetEnumerator:
An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.
You can get around this by iterating by index rather than using a foreach loop, but if you're removing an item you need to remember that everything below that will move up one element. So either you need to iterate backwards to remove items, or you need to remember to decrement the index.
Here's an approach which uses iterating by index forwards in terms of what we're looking at, but backwards in terms of looking for duplicates - stopping when we get to the index we're looking at. Note that this is still O(N2) - it's not as efficient as using Distinct:
// We're looking for duplicates *after* list[i], so we don't need to go as far
// as i being the very last element: there aren't any elements after it to be
// duplicates. (We could easily still just use list.Count, and the loop for j
// would just have 0 iterations.)
for (int i = 0; i < list.Count - 1; i++)
{
// Go backwards from the end, looking for duplicates of list[i]
for (int j = list.Count - 1; j > i; j--)
{
if (list[j] == list[i])
{
list.RemoveAt(j);
}
}
}
(For more details on Distinct, see my Edulinq post on it.)
As many people point out, you can use the Distinct method for your particular problem.
However, the problem you are actually having is that you are trying to modify the list when you iterate over it, which will not end well.
//This will not work.
foreach (string rs in list)
{
if (some_test)
{
list.Remove(rs); //Because of this line.
}
}
If you want do do something similar to this you need to find a way around this problem. Often it involves making a new array.
For this examle you can do the following
List newList = new ArrayList();
foreach (string rs in list)
{
if (!some_test)
{
newList.add(rs);
}
}
If you really want to create a "remove duplicates" method I would have done it in this fashion (pseudocode):
Hash cache_hash = new Hash(default false)
List new_list = new List
foreach string s in list
{
if not cache_hash[s]
{
new_list.add(s)
cache_hash[s] = true
}
}
list = new_list
This method is Ω(N) , so it is fairly fast on even large lists.
This question already has answers here:
Will using 'var' affect performance?
(12 answers)
Closed 9 years ago.
The language I use is C#.
Let we have a List of objects of type T,
List<T> collection = new List<T>{.....};
Say that we want to go over each item of collection. That can be done in many ways. Among of them, are the following two:
foreach(var item in collection)
{
// code goes here
}
and
foreach(T item in collection)
{
// code goes here
}
Does the second way be better than the first or not and why?
Thanks in advance for your answers.
They're both exactly the same. var is syntactic sugar for convenience. It makes no difference to the speed with which a List is traversed.
The rule of thumb I follow with var is to only use it if the type of the object is present on the right-hand side of an assignment, so in this case I'd prefer to explicitly specify the type in the foreach to make it clearer for other engineers, but it's down to personal choice. If you hover over a var in Visual Studio, it will display the type (assuming it can infer what is should be).
Quoting MSDN:
An implicitly typed local variable is strongly typed just as if you
had declared the type yourself, but the compiler determines the type.
So
var i = 10; // implicitly typed
int i = 10; //explicitly typed
Are exactly the same.
Now, for 'better' - It'll heavily depend on what's your parameter to judge that. If it's speed, then a for loop may be better than a foreach, and T[] better than List<T>, according to Patrick Smacchia. Main points:
for loops on List are a bit more than 2 times cheaper than foreach loops on List.
Looping on array is around 2 times cheaper than looping on List.
As a consequence, looping on array using for is 5 times cheaper than looping on List using foreach (which I believe, is what we all do).
Quote source: In .NET, which loop runs faster, 'for' or 'foreach'?
Reference: http://msdn.microsoft.com/en-us/library/bb383973.aspx
If you compare the IL code then you will see that the are really 100% the same.
var is only syntactic sugar:
C# Code:
List<int> collection = new List<int>();
collection.Add(1);
collection.Add(2);
collection.Add(3);
foreach (var myInt in collection)
{
Console.WriteLine(myInt);
}
foreach (var T in collection)
{
Console.WriteLine(T);
}
bool flag;
System.Collections.Generic.List<int> list = new System.Collections.Generic.List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
System.Collections.Generic.List<int>.Enumerator enumerator = list.GetEnumerator();
try
{
while (flag)
{
int i1 = enumerator.get_Current();
System.Console.WriteLine(i1);
flag = enumerator.MoveNext();
}
}
finally
{
enumerator.Dispose();
}
enumerator = list.GetEnumerator();
try
{
while (flag)
{
int i2 = enumerator.get_Current();
System.Console.WriteLine(i2);
flag = enumerator.MoveNext();
}
}
finally
{
enumerator.Dispose();
}
There is no faster way to iterate through same collection.
No matter what you use, your own loop or extension methods - this is all the same. When you use var - it still compiles to the same thing.
The only difference might be that if you use Dictionary, it will be faster than the List<T> or Collection in terms of searching for values. Dictionary was designed with optimization for search
1st way (with var) might be better for readability.
Consider this:
List<User> list = new List<User>();
var users = list.GroupBy(x => x.Name).OrderBy(x => x.Key);
foreach (var user in users)
{
//blah
}
vs
foreach (System.Linq.IGrouping<string, User> user in users)
{
}
I believe that was the main reason for having var in the first place.
atm I do it like this:
lock (LockObj)
{
foreach (var o in Oo)
{
var val = o.DateActive;
if (val.AddSeconds(30) < DateTime.Now) Oo.Remove(o);
}
}
and I get this error:
Collection was modified; enumeration operation may not execute
how this should be done?
You have to use a regular for loop.
for (int i = 0; i < Oo.Length; ++i)
{
var val = Oo[i];
if (val.AddSeconds(30) < DateTime.Now)
{
Oo.RemoveAt(i);
i--; // since we just removed an element
}
}
The reason you cannot edit a collection with a foreach loop is because foreach uses a readonly IEnumerator of the collection you are iterating.
you can't modify a collection you are enumerating..
to change it get a copy of it and change it.
for(var k in OO.ToList())
.....
or
use count and iterate the collection with index,
for (int i=0;i<OO.Count();i++)
.....
You simply cannot modify the collection if you are iterating with foreach. You have two options, Loop with For instead of foreach or create another Collection and modify that.
This problem is completely unrelated to locking.
If you add/remove elements from a List all iterators pointing to that list become invalid.
One alternative to using an iterator is manually working with indices. Then you can iterate backwards and remove elements with RemoveAt.
for(int i=Oo.Count-1;i>=0;i--)
{
var o=Oo[i];
if (o.DateActive.AddSeconds(30)<DateTime.Now)
Oo.RemoveAt(i);
}
Unfortunately this native implementation is O(n^2). If you write it in a more complex way where you first assign the elements to their new position and then truncate the list it becomes O(n).
Buf if Oo is a List<T> there is a much better solution. You can use Oo.RemoveAll(o=>o.DateActive.AddSeconds(30)<DateTime.Now). Unfortunately you there is no such extension method on IList<T> by default.
I'd write the code like this:
lock (LockObj)
{
DateTime deleteTime=DateTime.Now.AddSeconds(-30);
Oo.RemoveAll(o=>o.DateActive<deleteTime);
}
As a sidenote I'd personally use UTC times instead of local times for such code.
class Program
{
static void Main(string[] args)
{
List<OOItem> oo = new List<OOItem>();
oo.Add( new OOItem() { DateActive = DateTime.Now.AddSeconds(-31) });
lock(LockObj)
{
foreach( var item in oo.Where( ooItem => ooItem.DateActive.AddSeconds(30) < DateTime.Now ).ToArray())
{
oo.Remove(item);
}
}
Debug.Assert( oo.Count == 0);
}
}
public class OOItem
{
public DateTime DateActive { get; set; }
}
I'm going to suggest an approach that avoids messing around with decrementing loop indexes and other stuff that makes code difficult to understand.
I think the best bet is to write a nice query and then do a foreach over the result of turning the query into an array:
var inactives = from o in Oo
where o.DateActive < DateTime.Now
select o;
foreach (var o in inactives.ToArray())
{
Oo.Remove(o);
}
This avoids the issue of the collection changing and makes the code quite a bit more readable.
If you're a little more "functionally" oriented then here's another choice:
(from o in Oo
where o.DateActive < DateTime.Now
select o)
.ToList()
.ForEach(o => Oo.Remove(o));
Enjoy!
The problem is not related to the lock.
Use a for() loop instead of foreach().
I can't 100% replace your code because your code provides no hint of what collection type "Oo" is. Neither does the name "Oo". Perhaps one of the evils of var keyword overuse? Or maybe I just can't see enough of your code ;)
int size = Oo.Length();
for(int i = 0; i < size; i++){
if (Oo[i].AddSeconds(30) < DateTime.Now){
Oo[i].RemoveAt(i);
size--; // Compensate for new size after removal.
}
}
you can use Parallel.ForEach(oO, val=> { oO.Remove(val); })
Parallel doesn't have the IEnumerator problem !
What is the best way to iterate through a strongly-typed generic List in C#.NET and VB.NET?
For C#:
foreach(ObjectType objectItem in objectTypeList)
{
// ...do some stuff
}
Answer for VB.NET from Purple Ant:
For Each objectItem as ObjectType in objectTypeList
'Do some stuff '
Next
With any generic implementation of IEnumerable the best way is:
//C#
foreach( var item in listVariable) {
//do stuff
}
There is an important exception however. IEnumerable involves an overhead of Current() and MoveNext() that is what the foreach loop is actually compiled into.
When you have a simple array of structs:
//C#
int[] valueTypeArray;
for(int i=0; i < valueTypeArray.Length; ++i) {
int item = valueTypeArray[i];
//do stuff
}
Is quicker.
Update
Following a discussion with #Steven Sudit (see comments) I think my original advice may be out of date or mistaken, so I ran some tests:
// create a list to test with
var theList = Enumerable.Range(0, 100000000).ToList();
// time foreach
var sw = Stopwatch.StartNew();
foreach (var item in theList)
{
int inLoop = item;
}
Console.WriteLine("list foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
int cnt = theList.Count;
for (int i = 0; i < cnt; i++)
{
int inLoop = theList[i];
}
Console.WriteLine("list for : " + sw.Elapsed.ToString());
// now run the same tests, but with an array
var theArray = theList.ToArray();
sw.Reset();
sw.Start();
foreach (var item in theArray)
{
int inLoop = item;
}
Console.WriteLine("array foreach: " + sw.Elapsed.ToString());
sw.Reset();
sw.Start();
// time for
cnt = theArray.Length;
for (int i = 0; i < cnt; i++)
{
int inLoop = theArray[i];
}
Console.WriteLine("array for : " + sw.Elapsed.ToString());
Console.ReadKey();
So, I ran this in release with all optimisations:
list foreach: 00:00:00.5137506
list for : 00:00:00.2417709
array foreach: 00:00:00.1085653
array for : 00:00:00.0954890
And then debug without optimisations:
list foreach: 00:00:01.1289015
list for : 00:00:00.9945345
array foreach: 00:00:00.6405422
array for : 00:00:00.4913245
So it appears fairly consistent, for is quicker than foreach and arrays are quicker than generic lists.
However, this is across 100,000,000 iterations and the difference is about .4 of a second between the fastest and slowest methods. Unless you're doing massive performance critical loops it just isn't worth worrying about.
C#
myList<string>().ForEach(
delegate(string name)
{
Console.WriteLine(name);
});
Anonymous delegates are not currently implemented in VB.Net, but both C# and VB.Net should be able to do lambdas:
C#
myList<string>().ForEach(name => Console.WriteLine(name));
VB.Net
myList(Of String)().ForEach(Function(name) Console.WriteLine(name))
As Grauenwolf pointed out the above VB won't compile since the lambda doesn't return a value. A normal ForEach loop as others have suggested is probably the easiest for now, but as usual it takes a block of code to do what C# can do in one line.
Here's a trite example of why this might be useful: this gives you the ability to pass in the loop logic from another scope than where the IEnumerable exists, so you don't even have to expose it if you don't want to.
Say you have a list of relative url paths that you want to make absolute:
public IEnumerable<String> Paths(Func<String> formatter) {
List<String> paths = new List<String>()
{
"/about", "/contact", "/services"
};
return paths.ForEach(formatter);
}
So then you could call the function this way:
var hostname = "myhost.com";
var formatter = f => String.Format("http://{0}{1}", hostname, f);
IEnumerable<String> absolutePaths = Paths(formatter);
Giving you "http://myhost.com/about", "http://myhost.com/contact" etc. Obviously there are better ways to accomplish this in this specfic example, I'm just trying to demonstrate the basic principle.
For VB.NET:
For Each tmpObject as ObjectType in ObjectTypeList
'Do some stuff '
Next
Without knowing the internal implementation of a list, I think generally the best way to iterate over it would be a foreach loop. Because foreach uses an IEnumerator to walk over the list, it's up to the list itself to determine how to move from object to object.
If the internal implementation was, say, a linked list, then a simple for loop would be quite a bit slower than a foreach.
Does that make sense?
It depends on your application:
for loop, if efficiency is a priority
foreach loop or ForEach method, whichever communicates your intent more clearly
I may be missing something, but iterating through a generic list should be fairly simple if you use my examples below. The List<> class implements the IList and IEnumerable interfaces so that you can easily iterate through them basically any way you want.
The most efficient way would be to use a for loop:
for(int i = 0; i < genericList.Count; ++i)
{
// Loop body
}
You may also choose to use a foreach loop:
foreach(<insertTypeHere> o in genericList)
{
// Loop body
}