Richard Everett Richard Everett - 7 days ago 5
C# Question

foreach with generic List, detecting first iteration when using value type

When

foreach
ing through a generic list I often want to do something different for the first element in the list:

List<object> objs = new List<object>
{
new Object(),
new Object(),
new Object(),
new Object()
};

foreach (object o in objs)
{
if (o == objs.First())
{
System.Diagnostics.Debug.WriteLine("First object - do something special");
}
else
{
System.Diagnostics.Debug.WriteLine("object Do something else");
}
}


This will output:


First object - do something special
object Do something else
object Do something else
object Do something else


This is all fine and dandy.

However if my generic list is of a value type, this approach will fail.

List<int> ints = new List<int> { 0, 0, 0, 0 };
foreach (int i in ints)
{
if (i == ints.First())
{
System.Diagnostics.Debug.WriteLine("First int - do something special");
}
else
{
System.Diagnostics.Debug.WriteLine("int Do something else");
}
}


This will output:


First int - do something special
First int - do something special
First int - do something special
First int - do something special


Now I know I could recode this to add a
boolean
flag variable or traditional
for
loop, but I am wondering if there's any way to find out if a foreach loop is on the first iteration of its looping.

Answer

Well, you could code it using explicit iteration:

using(var iter = ints.GetEnumerator()) {
  if(iter.MoveNext()) {
     // do "first" with iter.Current

     while(iter.MoveNext()) {
       // do something with the rest of the data with iter.Current
     }
  }
}

The bool flag option (with foreach) is probably easier though... that is what I (almost) always do!

Another option would be LINQ:

if(ints.Any()) {
  var first = ints.First();
  // do something with first
}

foreach(var item in ints.Skip(1)) {
  // do something with the rest of them
}

The downside of the above is that it tries to look at the list 3 times... since we know it is a list, that is fine - but if all we had was an IEnumerable<T>, it would only be sensible to iterate it once (since the source might not be re-readable).

Comments