Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

.net

When foreaching 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.

like image 627
Richard Ev Avatar asked Jan 07 '09 15:01

Richard Ev


People also ask

Does foreach work with lists?

Using the CodeThe ForEach method of the List<T> (not IList<T> ) executes an operation for every object which is stored in the list. Normally it contains code to either read or modify every object which is in the list or to do something with list itself for every object.

How do you iterate through a List in C#?

Using foreach Statement The standard option to iterate over the List in C# is using a foreach loop. Then, we can perform any action on each element of the List. The following code example demonstrates its usage by displaying the contents of the list to the console.

What is foreach loop used for?

The foreach loop works only on arrays, and is used to loop through each key/value pair in an array.


2 Answers

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).

like image 145
Marc Gravell Avatar answered Sep 23 '22 13:09

Marc Gravell


A while ago I wrote SmartEnumerable (part of MiscUtil) which lets you know if the current element is the first or last, as well as its index. That may help you... it's part of MiscUtil, which is open source - you can take just SmartEnumerable under the same licence, of course.

Sample code (c'n'p from the web page):

using System;
using System.Collections.Generic;

using MiscUtil.Collections;

class Example
{
    static void Main(string[] args)
    {
        List<string> list = new List<string>();
        list.Add("a");
        list.Add("b");
        list.Add("c");
        list.Add("d");
        list.Add("e");

        foreach (SmartEnumerable<string>.Entry entry in
                 new SmartEnumerable<string>(list))
        {
            Console.WriteLine ("{0,-7} {1} ({2}) {3}",
                               entry.IsLast  ? "Last ->" : "",
                               entry.Value,
                               entry.Index,
                               entry.IsFirst ? "<- First" : "");
        }
    }
}

EDIT: Note that while it works with reference types with distinct references, it'll still fail if you give it a list where the first reference crops up elsewhere in the list.

like image 42
Jon Skeet Avatar answered Sep 21 '22 13:09

Jon Skeet