1053

Is there some rare language construct I haven't encountered (like the few I've learned recently, some on Stack Overflow) in C# to get a value representing the current iteration of a foreach loop?

For instance, I currently do something like this depending on the circumstances:

int i = 0;
foreach (Object o in collection)
{
    // ...
    i++;
}
AustinWBryan
  • 2,968
  • 3
  • 17
  • 35
Matt Mitchell
  • 37,997
  • 35
  • 111
  • 181
  • 2
    foreach casting retrieval is generally not going to me more optimized than just using index-based access on a collection, though in many cases it will be equal. The purpose of foreach is to make your code readable, but it (usually) adds a layer of indirection, which isn't free. – Brian Mar 26 '10 at 15:32
  • 10
    I would say the primary purpose of `foreach` is to provide a common iteration mechanism for all collections regardless of whether they are indexable (`List`) or not (`Dictionary`). – Brian Gideon Jul 23 '10 at 15:59
  • 2
    Hi Brian Gideon - definitely agree (this was a few years ago and I was far less experienced at the time). However, while `Dictionary` isn't indexable, an iteration of `Dictionary` does traverse it in a particular order (i.e. an Enumerator is indexable by the fact it yields elements sequentially). In this sense, we could say that we are not looking for the index within the collection, but rather the index of the current enumerated element within the enumeration (i.e. whether we are at the first or fifth or last enumerated element). – Matt Mitchell May 03 '11 at 02:28
  • 5
    foreach also allows the compiler to skip bounds checking each array access in the compiled code. Using for with an index will make the runtime check whether your index access is safe. – IvoTops Aug 22 '12 at 09:00
  • 1
    But it's false. If you don't change the iteration variable of a for loop within the loop, the compiler knows what its bounds are and doesn't need to check them again. This is such a common case that any decent compiler will implement it. – Jim Balter Oct 26 '13 at 00:52
  • It's good. Does it lack readability? I don't think so. Too much writing? Typing cost is negligible when the phrase is not used very, very often. Low level optimization? Don't do that in C#. Just don't. Some sort of elegance? Well, in that case, there is `WithIndex` syntax that is nice, but what you have is good to. But do not use LINQ just for the sake of elegance. It's kind of a code smell to me. I use LINQ only when I can achieve a considerable improvement in readability and / or coding speed. Using LINQ for a simple loop is a no-no. – Harry Dec 16 '20 at 12:11

35 Answers35

758

Ian Mercer posted a similar solution as this on Phil Haack's blog:

foreach (var item in Model.Select((value, i) => new { i, value }))
{
    var value = item.value;
    var index = item.i;
}

This gets you the item (item.value) and its index (item.i) by using this overload of LINQ's Select:

the second parameter of the function [inside Select] represents the index of the source element.

The new { i, value } is creating a new anonymous object.

Heap allocations can be avoided by using ValueTuple if you're using C# 7.0 or later:

foreach (var item in Model.Select((value, i) => ( value, i )))
{
    var value = item.value;
    var index = item.i;
}

You can also eliminate the item. by using automatic destructuring:

<ol>
foreach ((MyType value, Int32 i) in Model.Select((value, i) => ( value, i )))
{
    <li id="item_@i">@value</li>
}
</ol>
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
bcahill
  • 7,793
  • 1
  • 15
  • 10
  • 9
    That solution is nice for the case of a Razor template where the neatness of the template is a non-trivial design concern and you are also wanting to use the index of every item that is enumerated. However, do bear in mind that the object allocation from 'wrapping' adds expense (in space and time) on top of the (unavoidable) incrementing of an integer. – David Bullock Feb 25 '14 at 11:14
  • 3
    pure awesomeness, but where is that documented.... I mean two parameters in the Select delegate, I never saw that... and I can't find a documentation explanation..... experimenting with that expression I saw that value doesn't mean anything and only the position matters, first parameter the element, second parameter the index. – mjsr Jul 15 '15 at 20:25
  • 6
    @mjsr The documentation is [here](https://msdn.microsoft.com/en-us/library/bb534869(v=vs.110).aspx). – Thorkil Holm-Jacobsen Sep 15 '15 at 12:52
  • 34
    Sorry - that's clever, but is it really more readable than creating an index outside the foreach and incrementing it each loop? – jbyrd Oct 17 '17 at 20:13
  • 17
    With the later C# versions so you also use tuples, so you'll have something like this: foreach (var (item, i) in Model.Select((v, i) => (v, i))) Allows you to access the item and index (i) directly inside the for-loop with tuple deconstruction. – Haukman Jan 08 '18 at 22:25
  • 8
    Can someone explain to me why this is a good answer (over 450 upvotes at the time of writing)? As far as I can see it's more difficult to understand than simply incrementing a counter, is hence less maintainable, it uses more memory, and it is probably slower. Am I missing something? – Rich N Oct 09 '18 at 17:24
  • 1
    @RichN The Linq `.Select( T item, Int32 index )` method is now well-known amongst most C# programmers today. It's only confusing if you're not yet familiar with Linq and its functional style of programming. – Dai Jan 25 '19 at 06:51
  • 3
    Has anyone done any performance and memory usage tests with the `tuple` version compared to the incrementing counter? I'm sure others would like to know if performance and memory was a factor in their coding requirements. – thames Mar 07 '19 at 03:58
  • 2
    @RichN B/c `for` and `foreach` loops ain't "cool" nowadays (/s). Chaining is. The problem is that LINQ doesn't have `forEach` _on purpose_ (as [Eric Lippert explains beautifully](https://docs.microsoft.com/en-us/archive/blogs/ericlippert/foreach-vs-foreach)). That's b/c foreach is solely used for side effects, breaking the chaining metaphor. LINQ calls that anti-pattern [I think Eric'd say it should be anti-pattern in other languages as well]. So you see `foreach` caught in the "stop using `for` loops; start chaining" coolness vs. "there's no foreach chaining in C# [LINQ] on purpose" crossfire – ruffin Jul 22 '20 at 17:17
597

The foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.

This Enumerator has a method and a property:

  • MoveNext()
  • Current

Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.

The concept of an index is foreign to the concept of enumeration, and cannot be done.

Because of that, most collections are able to be traversed using an indexer and the for loop construct.

I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.

Neuron
  • 3,776
  • 3
  • 24
  • 44
FlySwat
  • 160,042
  • 69
  • 241
  • 308
  • 193
    "Obviously, the concept of an index is foreign to the concept of enumeration, and cannot be done." -- This is nonsense, as the answers by David B and bcahill make clear. An index is an enumeration over a range, and there's no reason one cannot enumerate two things in parallel ... that's exactly what the indexing form of Enumerable.Select does. – Jim Balter Oct 26 '13 at 00:57
  • 13
    Basic code example: `for(var i = 0; i < myList.Count; i ++){System.Diagnostics.Debug.WriteLine(i);}` – Chad Hedgcock Apr 14 '15 at 17:53
  • 1
    @JimBalter: A Linked List is an example of an IEnumerable that doesn't have an index. FlySwat's answer is correct, although maybe you were taking issue with his word "obviously", in which case, I agree; It's not so obvious to many. – Pretzel Feb 01 '16 at 20:17
  • 6
    @Pretzel The statement which I quoted is (obviously) not correct, and I explained why. The fact Linked List "doesn't have an index" is completely irrelevant and shows extraordinary confusion. – Jim Balter Feb 02 '16 at 00:34
  • 1
    @JimBalter: Well, I'm not going to argue with you. Maybe Microsoft should have called it I-Iterable instead of IEnumerable (which, I'll conceded, does imply a number.) But the implementation is how it is. There's no index. (I'm guessing for thread-safety reasons...) – Pretzel Feb 02 '16 at 16:40
  • P.S. Just read https://msdn.microsoft.com/en-us/library/bb534869%28v=vs.100%29.aspx, which I've referred to several times now. Pay some attention to "you can call this method as an instance method on *any object of type IEnumerable*" – Jim Balter Feb 02 '16 at 20:41
  • 3
    The bottom line is that "A Linked List is an example of an IEnumerable that doesn't have an index" is a strawman that is completely irrelevant. No one ever claimed that all IEnumerables "have an index". – Jim Balter Feb 02 '16 at 22:48
  • 12
    Pretzel: Your use of Jon Skeet as a model citizen is mistaken, as he will browbeat (and downvote) someone who doesn't agree with him, as I've experienced. Jim Balter: Some of your comments were overly aggressive and you could have presented your points with less anger and more education. – Suncat2000 Aug 12 '16 at 19:22
  • Being curious, is the simplified statement "the concept of an index is foreign to the concept of enumeration" correct, then? – Marson Mao Feb 10 '17 at 09:10
  • 9
    @Pretzel Jim's point is that as long as you can map the elements to a sequence of integers, you can index it. That the class itself does not store an index is beside the point. Additionally, that the linked list *does* have an order only strengthens Jim's position. All you need to do is number each element in order. Specifically, you can achieve this by incrementing a count *while* you iterate, or you could generate a list of integers with the same length and then zip them (as in Python's [`zip`](https://docs.python.org/3/library/functions.html#zip) function). – jpmc26 Sep 02 '17 at 01:29
  • 6
    This is a pathetic non-answer. Can you imagine if this were posted onto a Python or Rust question? People would laugh at it while posting pointer to the `enumerate` function. – Colonel Thirty Two Apr 05 '19 at 01:54
  • 3
    Can we switch this 'answer' out with @bcahill's answer, as his addresses the question asked and has more upvotes than this one at present (489 vs 520)? – Dave Thompson May 13 '19 at 09:31
  • 4
    Enumerable literally means "can be numbered". That the API or underlying data structure doesn't provide a means for random access is another thing entirely different. – Trinidad Jul 12 '19 at 06:33
  • 1
    How Microsoft of you, Microsoft – refaelio Apr 13 '20 at 12:33
  • Just to be clear, the question asks for an index of "the current iteration of a foreach loop", which is not the same as the natural index of the enumerable (if there even is one). If your enumerable represents e.g. items 5, 6, 7 in some list, then you're right there's no way to get that. But the OP actually wanted 0, 1, 2 in that case, which of course is possible. Basically this is a correct answer to a different question. – Arthur Tacca Mar 12 '21 at 08:52
286

Finally C#7 has a decent syntax for getting an index inside of a foreach loop (i. e. tuples):

foreach (var (item, index) in collection.WithIndex())
{
    Debug.WriteLine($"{index}: {item}");
}

A little extension method would be needed:

public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)       
   => self.Select((item, index) => (item, index)); 
user1414213562
  • 3,353
  • 1
  • 11
  • 9
  • 20
    This answer is underrated, having the tuples is much cleaner – Todd Sep 20 '17 at 01:15
  • 19
    Modified to handle null collections: `public static IEnumerable WithIndex(this IEnumerable self) => self?.Select((item, index) => (item, index)) ?? new List();` – 2Toad Nov 25 '18 at 05:33
  • 1
    Nice one. I really like this solution the most. – FranzHuber23 Sep 25 '19 at 09:12
  • 1
    This is the best answer – w0ns88 Jan 28 '20 at 13:53
  • 5
    It might be useful to call the method `Enumerated` to be more recognizable for people used to [other languages](https://developer.apple.com/documentation/swift/array/1687832-enumerated) (and perhaps swap the order of the tuple parameters too). Not that `WithIndex` isn't obvious anyway. – FernAndr Jan 30 '20 at 09:33
  • @2Toad For the null condition you could also use `Enumerable.Empty()` as more efficient than creating an empty list, I think. – Dan Diplo Oct 19 '20 at 08:58
  • This should be the solution now – Nomnom Nov 25 '20 at 19:45
123

Could do something like this:

public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}
Brad Wilson
  • 61,606
  • 8
  • 70
  • 82
  • 14
    That doesn't "really" solve the problem. The idea is good but it doesn't avoid the additional counting variable – Atmocreations Dec 31 '09 at 11:52
  • This does not work if we have a return statement within our for loop, if you change "ForEachWithIndex" for that, then it is not generic, better off writing a regular for loop – Shankar Raju Aug 15 '12 at 16:39
  • Your ForEachWithIndex call is equivalent to this one using the Linq Select that takes a string and an index: `values.Select((item, idx) => { Console.WriteLine("{0}: {1}", idx, item); return item; }).ToList();` – user2023861 Jan 28 '16 at 14:07
103

I disagree with comments that a for loop is a better choice in most cases.

foreach is a useful construct, and not replaceble by a for loop in all circumstances.

For example, if you have a DataReader and loop through all records using a foreach it automatically calls the Dispose method and closes the reader (which can then close the connection automatically). This is therefore safer as it prevents connection leaks even if you forget to close the reader.

(Sure it is good practise to always close readers but the compiler is not going to catch it if you don't - you can't guarantee you have closed all readers but you can make it more likely you won't leak connections by getting in the habit of using foreach.)

There may be other examples of the implicit call of the Dispose method being useful.

SteveC
  • 13,636
  • 21
  • 86
  • 155
mike nelson
  • 18,814
  • 13
  • 59
  • 66
  • 2
    Thanks for pointing this out. Rather subtle. You can get more information at http://www.pvle.be/2010/05/foreach-statement-calls-dispose-on-ienumerator/ and http://msdn.microsoft.com/en-us/library/aa664754(VS.71).aspx. – Mark Meuer Jun 17 '11 at 14:22
  • +1. I was writing more in detail about how `foreach` is different from `for` (and closer to `while`) on [Programmers.SE](http://programmers.stackexchange.com/a/178225/6605). – Arseni Mourzenko Apr 07 '13 at 03:22
67

Literal Answer -- warning, performance may not be as good as just using an int to track the index. At least it is better than using IndexOf.

You just need to use the indexing overload of Select to wrap each item in the collection with an anonymous object that knows the index. This can be done against anything that implements IEnumerable.

System.Collections.IEnumerable collection = Enumerable.Range(100, 10);

foreach (var o in collection.OfType<object>().Select((x, i) => new {x, i}))
{
    Console.WriteLine("{0} {1}", o.i, o.x);
}
SteveC
  • 13,636
  • 21
  • 86
  • 155
Amy B
  • 100,846
  • 20
  • 127
  • 174
  • 3
    The only reason to use OfType() instead of Cast() is if some items in the enumeration might fail an explicit cast. For object, this will never be the case. – dahlbyk Jun 26 '09 at 00:09
  • 15
    Sure, except for the other reason to use OfType instead of Cast - which is that I never use Cast. – Amy B Jun 26 '09 at 02:02
  • Why was the OfType() (or Cast, if preferred) needed at all? Select can be called right on collection, no? – StayOnTarget Dec 02 '20 at 17:36
  • @UuDdLrLrSs No. Select requires a type parameter. non-generic IEnumerable has no type parameter to supply. – Amy B Dec 02 '20 at 23:28
  • @AmyB thanks! I overlooked that collection was IEnumerable only. – StayOnTarget Dec 02 '20 at 23:29
44

Using LINQ, C# 7, and the System.ValueTuple NuGet package, you can do this:

foreach (var (value, index) in collection.Select((v, i)=>(v, i))) {
    Console.WriteLine(value + " is at index " + index);
}

You can use the regular foreach construct and be able to access the value and index directly, not as a member of an object, and keeps both fields only in the scope of the loop. For these reasons, I believe this is the best solution if you are able to use C# 7 and System.ValueTuple.

Pavel
  • 858
  • 1
  • 13
  • 18
  • How is this different from [user1414213562's answer](https://stackoverflow.com/a/39997157/145173)? – Edward Brey Apr 08 '19 at 13:36
  • @EdwardBrey I suppose it isn't. This question has a lot of answers, I probably just missed it or didn't notice what it was doing because he separated some of the logic out into an extension method. – Pavel Apr 08 '19 at 16:12
  • 2
    This is different because .Select is built-in from LINQ. You don't have to write your own function? You will need to have VS install "System.ValueTuple" though. – Anton Dec 17 '19 at 19:13
36

Using @FlySwat's answer, I came up with this solution:

//var list = new List<int> { 1, 2, 3, 4, 5, 6 }; // Your sample collection

var listEnumerator = list.GetEnumerator(); // Get enumerator

for (var i = 0; listEnumerator.MoveNext() == true; i++)
{
  int currentItem = listEnumerator.Current; // Get current item.
  //Console.WriteLine("At index {0}, item is {1}", i, currentItem); // Do as you wish with i and  currentItem
}

You get the enumerator using GetEnumerator and then you loop using a for loop. However, the trick is to make the loop's condition listEnumerator.MoveNext() == true.

Since the MoveNext method of an enumerator returns true if there is a next element and it can be accessed, making that the loop condition makes the loop stop when we run out of elements to iterate over.

Gezim
  • 6,076
  • 10
  • 52
  • 76
  • 12
    There's no need to compare listEnumerator.MoveNext() == true. That's like asking the computer if true == true? :) Just say if listEnumerator.MoveNext() { } – Zesty Nov 07 '13 at 08:12
  • 11
    @Zesty, you're absolutely correct. I felt that it's more readable to add it in this case especially for people who aren't used to entering anything other than i < blahSize as a condition. – Gezim Nov 07 '13 at 17:36
  • @Gezim I don't mind predicates here, but I get your point in that this doesn't look like a predicate. – John Dvorak Jun 30 '16 at 10:22
  • 2
    You should dispose the enumerator. – Antonín Lejsek Dec 16 '17 at 21:02
  • @AntonínLejsek The enumerator does not implement `IDisposable`. – Edward Brey Apr 08 '19 at 13:38
  • 1
    @EdwardBrey you are right, it is a good point. But speaking about the `listEnumerator` here, it is a generic enumerator and as such it does implement `IDisposable` and should be disposed. – Antonín Lejsek Apr 09 '19 at 02:56
  • 1
    @AntonínLejsek Good catch for `List`'s enumerator. It implements `System.Collections.Generic.IEnumerator`, which inherits `IDisposable`. The enumerator for `List` doesn't do anything in `Dispose` and doesn't have a finalizer, so calling `Dispose` in this case has no effect, but it could for other enumerables. – Edward Brey Apr 09 '19 at 11:24
36

There's nothing wrong with using a counter variable. In fact, whether you use for, foreach while or do, a counter variable must somewhere be declared and incremented.

So use this idiom if you're not sure if you have a suitably-indexed collection:

var i = 0;
foreach (var e in collection) {
   // Do stuff with 'e' and 'i'
   i++;
}

Else use this one if you know that your indexable collection is O(1) for index access (which it will be for Array and probably for List<T> (the documentation doesn't say), but not necessarily for other types (such as LinkedList)):

// Hope the JIT compiler optimises read of the 'Count' property!
for (var i = 0; i < collection.Count; i++) {
   var e = collection[i];
   // Do stuff with 'e' and 'i'
}

It should never be necessary to 'manually' operate the IEnumerator by invoking MoveNext() and interrogating Current - foreach is saving you that particular bother ... if you need to skip items, just use a continue in the body of the loop.

And just for completeness, depending on what you were doing with your index (the above constructs offer plenty of flexibility), you might use Parallel LINQ:

// First, filter 'e' based on 'i',
// then apply an action to remaining 'e'
collection
    .AsParallel()
    .Where((e,i) => /* filter with e,i */)
    .ForAll(e => { /* use e, but don't modify it */ });

// Using 'e' and 'i', produce a new collection,
// where each element incorporates 'i'
collection
    .AsParallel()
    .Select((e, i) => new MyWrapper(e, i));

We use AsParallel() above, because it's 2014 already, and we want to make good use of those multiple cores to speed things up. Further, for 'sequential' LINQ, you only get a ForEach() extension method on List<T> and Array ... and it's not clear that using it is any better than doing a simple foreach, since you are still running single-threaded for uglier syntax.

Community
  • 1
  • 1
David Bullock
  • 5,331
  • 2
  • 30
  • 40
  • In my view, this is the best answer in terms of weighing readability and ensuring there is bounds safety – Dean P May 01 '21 at 14:01
26

You could wrap the original enumerator with another that does contain the index information.

foreach (var item in ForEachHelper.WithIndex(collection))
{
    Console.Write("Index=" + item.Index);
    Console.Write(";Value= " + item.Value);
    Console.Write(";IsLast=" + item.IsLast);
    Console.WriteLine();
}

Here is the code for the ForEachHelper class.

public static class ForEachHelper
{
    public sealed class Item<T>
    {
        public int Index { get; set; }
        public T Value { get; set; }
        public bool IsLast { get; set; }
    }

    public static IEnumerable<Item<T>> WithIndex<T>(IEnumerable<T> enumerable)
    {
        Item<T> item = null;
        foreach (T value in enumerable)
        {
            Item<T> next = new Item<T>();
            next.Index = 0;
            next.Value = value;
            next.IsLast = false;
            if (item != null)
            {
                next.Index = item.Index + 1;
                yield return item;
            }
            item = next;
        }
        if (item != null)
        {
            item.IsLast = true;
            yield return item;
        }            
    }
}
Brian Gideon
  • 45,093
  • 12
  • 98
  • 145
  • This won't actually return the index of the item. Instead, it will return the index inside the enumerated list, which may only be a sublist of the list, thereby giving you accurate data only when the sublist and the list are of equal size. Basically, any time the collection has objects in it not in the requested type your index will be incorrect. – Lucas B Jul 23 '10 at 13:11
  • 7
    @Lucas: No, but it will return the index of the current foreach iteration. That was the question. – Brian Gideon Jul 23 '10 at 13:32
21

Here's a solution I just came up with for this problem

Original code:

int index=0;
foreach (var item in enumerable)
{
    blah(item, index); // some code that depends on the index
    index++;
}

Updated code

enumerable.ForEach((item, index) => blah(item, index));

Extension Method:

    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
    {
        var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
        enumerable.Select((item, i) => 
            {
                action(item, i);
                return unit;
            }).ToList();

        return pSource;
    }
mat3
  • 779
  • 6
  • 12
19

Just add your own index. Keep it simple.

int i = 0;
foreach (var item in Collection)
{
    item.index = i;
    ++i;
}
conterio
  • 869
  • 1
  • 9
  • 20
18

Why foreach ?!

The simplest way is using for instead of foreach if you are using List:

for (int i = 0 ; i < myList.Count ; i++)
{
    // Do something...
}

Or if you want use foreach:

foreach (string m in myList)
{
     // Do something...
}

You can use this to know the index of each loop:

myList.indexOf(m)
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Parsa
  • 840
  • 12
  • 24
  • 12
    indexOf solution is invalid for list with duplicates and is also very slow. – tymtam Nov 17 '16 at 00:03
  • 2
    The issue to be avoided is where you traverse the IEnumerable multiple times, e.g. to get the count of items and then each item. This has implications when the IEnumerable is the result of a database query for example. – David Clarke Jan 12 '18 at 01:18
  • 2
    myList.IndexOf() is O(n), so your loop will be O(n^2). – Patrick Beard Nov 08 '19 at 18:06
16

It's only going to work for a List and not any IEnumerable, but in LINQ there's this:

IList<Object> collection = new List<Object> { 
    new Object(), 
    new Object(), 
    new Object(), 
    };

foreach (Object o in collection)
{
    Console.WriteLine(collection.IndexOf(o));
}

Console.ReadLine();

@Jonathan I didn't say it was a great answer, I just said it was just showing it was possible to do what he asked :)

@Graphain I wouldn't expect it to be fast - I'm not entirely sure how it works, it could reiterate through the entire list each time to find a matching object, which would be a helluvalot of compares.

That said, List might keep an index of each object along with the count.

Jonathan seems to have a better idea, if he would elaborate?

It would be better to just keep a count of where you're up to in the foreach though, simpler, and more adaptable.

crucible
  • 2,901
  • 2
  • 23
  • 35
15

C# 7 finally gives us an elegant way to do this:

static class Extensions
{
    public static IEnumerable<(int, T)> Enumerate<T>(
        this IEnumerable<T> input,
        int start = 0
    )
    {
        int i = start;
        foreach (var t in input)
        {
            yield return (i++, t);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var s = new string[]
        {
            "Alpha",
            "Bravo",
            "Charlie",
            "Delta"
        };

        foreach (var (i, t) in s.Enumerate())
        {
            Console.WriteLine($"{i}: {t}");
        }
    }
}
Paul Mitchell
  • 3,061
  • 17
  • 21
11

This answer: lobby the C# language team for direct language support.

The leading answer states:

Obviously, the concept of an index is foreign to the concept of enumeration, and cannot be done.

While this is true of the current C# language version (2020), this is not a conceptual CLR/Language limit, it can be done.

The Microsoft C# language development team could create a new C# language feature, by adding support for a new Interface IIndexedEnumerable

foreach (var item in collection with var index)
{
    Console.WriteLine("Iteration {0} has value {1}", index, item);
}

//or, building on @user1414213562's answer
foreach (var (item, index) in collection)
{
    Console.WriteLine("Iteration {0} has value {1}", index, item);
}

If foreach () is used and with var index is present, then the compiler expects the item collection to declare IIndexedEnumerable interface. If the interface is absent, the compiler can polyfill wrap the source with an IndexedEnumerable object, which adds in the code for tracking the index.

interface IIndexedEnumerable<T> : IEnumerable<T>
{
    //Not index, because sometimes source IEnumerables are transient
    public long IterationNumber { get; }
}

Later, the CLR can be updated to have internal index tracking, that is only used if with keyword is specified and the source doesn't directly implement IIndexedEnumerable

Why:

  • Foreach looks nicer, and in business applications, foreach loops are rarely a performance bottleneck
  • Foreach can be more efficient on memory. Having a pipeline of functions instead of converting to new collections at each step. Who cares if it uses a few more CPU cycles when there are fewer CPU cache faults and fewer garbage collections?
  • Requiring the coder to add index-tracking code, spoils the beauty
  • It's quite easy to implement (please Microsoft) and is backward compatible

While most people here are not Microsoft employees, this is a correct answer, you can lobby Microsoft to add such a feature. You could already build your own iterator with an extension function and use tuples, but Microsoft could sprinkle the syntactic sugar to avoid the extension function

Todd
  • 14,946
  • 6
  • 42
  • 56
  • Wait, so does this language feature already exist, or is it proposed for the future? – Pavel Sep 18 '17 at 15:22
  • 1
    @Pavel I updated the answer to be clear. This answer was provided to counter the leading answer which states "Obviously, the concept of an index is foreign to the concept of enumeration, and cannot be done." – Todd Sep 20 '17 at 01:08
9
int index;
foreach (Object o in collection)
{
    index = collection.indexOf(o);
}

This would work for collections supporting IList.

sth
  • 200,334
  • 49
  • 262
  • 354
Sachin
  • 870
  • 6
  • 7
  • 70
    Two problems: 1) This is `O(n^2)` since in most implementations `IndexOf` is `O(n)`. 2) This fails if there are duplicate items in the list. – CodesInChaos Sep 14 '11 at 19:08
  • 16
    Note: O(n^2) means this could be disastrously slow for a big collection. – O'Rooney Nov 14 '11 at 00:58
  • Great invention to use IndexOf method! This is what I was looking for to get the index (number) in foreach loop! Big Thx – Mitja Bonca Feb 27 '13 at 09:50
  • 20
    God, I hope you did not use that! :( It DOES use that variable you did't want to create - in fact, it will create n+1 ints because that function has to create one in order to return, too, - and that indexof search is much, much slower than one integer increment operation in every step. Why won't people vote this answer down? – canahari May 19 '13 at 22:42
  • 14
    Don't use this answer, I found the hard truth mentioned in one of the comments. "This fails if there are duplicate items in the list."!!! – Bruce May 23 '14 at 07:32
  • helpful while in debug session – Amit Sep 29 '16 at 04:44
9

This is how I do it, which is nice for its simplicity/brevity, but if you're doing a lot in the loop body obj.Value, it is going to get old pretty fast.

foreach(var obj in collection.Select((item, index) => new { Index = index, Value = item }) {
    string foo = string.Format("Something[{0}] = {1}", obj.Index, obj.Value);
    ...
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Ian Henry
  • 21,297
  • 4
  • 47
  • 60
6

Better to use keyword continue safe construction like this

int i=-1;
foreach (Object o in collection)
{
    ++i;
    //...
    continue; //<--- safe to call, index will be increased
    //...
}
ardila
  • 1,237
  • 1
  • 12
  • 23
user426810
  • 69
  • 1
  • 1
5

If the collection is a list, you can use List.IndexOf, as in:

foreach (Object o in collection)
{
    // ...
    @collection.IndexOf(o)
}
nobody
  • 19,010
  • 17
  • 53
  • 73
ssaeed
  • 399
  • 1
  • 6
  • 11
  • 13
    And now the algorithm is O(n^2) (if not worse). I would think *very* carefully before using this. Its also a duplicate of @crucible 's answer – BradleyDotNET Jan 05 '15 at 18:26
  • 1
    @BradleyDotNET is exactly right, don't use this version. – Oskar Jan 15 '16 at 11:16
  • 1
    Be careful with this! If you've got a duplicated item in your list, it will get the position of the first one! – Sonhja Jul 15 '16 at 09:00
5

You can write your loop like this:

var s = "ABCDEFG";
foreach (var item in s.GetEnumeratorWithIndex())
{
    System.Console.WriteLine("Character: {0}, Position: {1}", item.Value, item.Index);
}

After adding the following struct and extension method.

The struct and extension method encapsulate Enumerable.Select functionality.

public struct ValueWithIndex<T>
{
    public readonly T Value;
    public readonly int Index;

    public ValueWithIndex(T value, int index)
    {
        this.Value = value;
        this.Index = index;
    }

    public static ValueWithIndex<T> Create(T value, int index)
    {
        return new ValueWithIndex<T>(value, index);
    }
}

public static class ExtensionMethods
{
    public static IEnumerable<ValueWithIndex<T>> GetEnumeratorWithIndex<T>(this IEnumerable<T> enumerable)
    {
        return enumerable.Select(ValueWithIndex<T>.Create);
    }
}
Satisfied
  • 51
  • 1
  • 2
4

I don't think this should be quite efficient, but it works:

@foreach (var banner in Model.MainBanners) {
    @Model.MainBanners.IndexOf(banner)
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Bart Calixto
  • 17,850
  • 9
  • 72
  • 108
3

I built this in LINQPad:

var listOfNames = new List<string>(){"John","Steve","Anna","Chris"};

var listCount = listOfNames.Count;

var NamesWithCommas = string.Empty;

foreach (var element in listOfNames)
{
    NamesWithCommas += element;
    if(listOfNames.IndexOf(element) != listCount -1)
    {
        NamesWithCommas += ", ";
    }
}

NamesWithCommas.Dump();  //LINQPad method to write to console.

You could also just use string.join:

var joinResult = string.Join(",", listOfNames);
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Warren LaFrance
  • 472
  • 6
  • 18
  • You can also use the string.join in c# For example: var joinResult = string.Join("," ,listOfNames);' – Warren LaFrance Dec 17 '13 at 17:38
  • 1
    Can someone explain to me what's this O(n*n) thing ? – Axel Jan 09 '17 at 21:59
  • @Axel it basically means that the operations required to calculate the result increase quadratically, i.e. if there are `n` items then the operations are `n * n`, or `n`-squared. https://en.wikipedia.org/wiki/Time_complexity#Table_of_common_time_complexities – Richard Hansell Sep 11 '18 at 14:09
3

My solution for this problem is an extension method WithIndex(),

http://code.google.com/p/ub-dotnet-utilities/source/browse/trunk/Src/Utilities/Extensions/EnumerableExtensions.cs

Use it like

var list = new List<int> { 1, 2, 3, 4, 5, 6 };    

var odd = list.WithIndex().Where(i => (i.Item & 1) == 1);
CollectionAssert.AreEqual(new[] { 0, 2, 4 }, odd.Select(i => i.Index));
CollectionAssert.AreEqual(new[] { 1, 3, 5 }, odd.Select(i => i.Item));
ulrichb
  • 18,344
  • 6
  • 67
  • 87
3

For interest, Phil Haack just wrote an example of this in the context of a Razor Templated Delegate (http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx)

Effectively he writes an extension method which wraps the iteration in an "IteratedItem" class (see below) allowing access to the index as well as the element during iteration.

public class IndexedItem<TModel> {
  public IndexedItem(int index, TModel item) {
    Index = index;
    Item = item;
  }

  public int Index { get; private set; }
  public TModel Item { get; private set; }
}

However, while this would be fine in a non-Razor environment if you are doing a single operation (i.e. one that could be provided as a lambda) it's not going to be a solid replacement of the for/foreach syntax in non-Razor contexts.

Matt Mitchell
  • 37,997
  • 35
  • 111
  • 181
2

How about something like this? Note that myDelimitedString may be null if myEnumerable is empty.

IEnumerator enumerator = myEnumerable.GetEnumerator();
string myDelimitedString;
string current = null;

if( enumerator.MoveNext() )
    current = (string)enumerator.Current;

while( null != current)
{
    current = (string)enumerator.Current; }

    myDelimitedString += current;

    if( enumerator.MoveNext() )
        myDelimitedString += DELIMITER;
    else
        break;
}
2

Unless your collection can return the index of the object via some method, the only way is to use a counter like in your example.

However, when working with indexes, the only reasonable answer to the problem is to use a for loop. Anything else introduces code complexity, not to mention time and space complexity.

Joseph Daigle
  • 44,480
  • 10
  • 46
  • 70
2

I don't believe there is a way to get the value of the current iteration of a foreach loop. Counting yourself, seems to be the best way.

May I ask, why you would want to know?

It seems that you would most likley be doing one of three things:

1) Getting the object from the collection, but in this case you already have it.

2) Counting the objects for later post processing...the collections have a Count property that you could make use of.

3) Setting a property on the object based on its order in the loop...although you could easily be setting that when you added the object to the collection.

bryansh
  • 293
  • 2
  • 8
  • 4) The case I've hit several times is something different that has to be done on the first or last pass--say a list of objects you are going to print and you need commas between items but not after the last item. – Loren Pechtel Aug 20 '10 at 23:01
2

I just had this problem, but thinking around the problem in my case gave the best solution, unrelated to the expected solution.

It could be quite a common case, basically, I'm reading from one source list and creating objects based on them in a destination list, however, I have to check whether the source items are valid first and want to return the row of any error. At first-glance, I want to get the index into the enumerator of the object at the Current property, however, as I am copying these elements, I implicitly know the current index anyway from the current destination. Obviously it depends on your destination object, but for me it was a List, and most likely it will implement ICollection.

i.e.

var destinationList = new List<someObject>();
foreach (var item in itemList)
{
  var stringArray = item.Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);

  if (stringArray.Length != 2)
  {
    //use the destinationList Count property to give us the index into the stringArray list
    throw new Exception("Item at row " + (destinationList.Count + 1) + " has a problem.");
  }
  else
  {
    destinationList.Add(new someObject() { Prop1 = stringArray[0], Prop2 = stringArray[1]});
  }
}

Not always applicable, but often enough to be worth mentioning, I think.

Anyway, the point being that sometimes there is a non-obvious solution already in the logic you have...

nicodemus13
  • 2,060
  • 1
  • 17
  • 30
2
//using foreach loop how to get index number:
    
foreach (var result in results.Select((value, index) => new { index, value }))
    {
     //do something
    }
usman tahir
  • 89
  • 1
  • 4
  • 5
    While this code may answer the question, providing additional context regarding *how* and/or *why* it solves the problem would improve the answer's long-term value. – Klaus Gütter Jul 17 '20 at 12:17
  • This is just a repeat of [this existing answer](https://stackoverflow.com/a/11437562). – Pang Mar 29 '21 at 07:44
2

I wasn't sure what you were trying to do with the index information based on the question. However, in C#, you can usually adapt the IEnumerable.Select method to get the index out of whatever you want. For instance, I might use something like this for whether a value is odd or even.

string[] names = { "one", "two", "three" };
var oddOrEvenByName = names
    .Select((name, index) => new KeyValuePair<string, int>(name, index % 2))
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

This would give you a dictionary by name of whether the item was odd (1) or even (0) in the list.

Kasey Speakman
  • 3,631
  • 28
  • 39
1

This way you can use the index and value using LINQ:

ListValues.Select((x, i) => new { Value = x, Index = i }).ToList().ForEach(element =>
    {
        // element.Index
        // element.Value

    });
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
0

Here is another solution to this problem, with a focus on keeping the syntax as close to a standard foreach as possible.

This sort of construct is useful if you are wanting to make your views look nice and clean in MVC. For example instead of writing this the usual way (which is hard to format nicely):

 <%int i=0;
 foreach (var review in Model.ReviewsList) { %>
    <div id="review_<%=i%>">
        <h3><%:review.Title%></h3>                      
    </div>
    <%i++;
 } %>

You could instead write this:

 <%foreach (var review in Model.ReviewsList.WithIndex()) { %>
    <div id="review_<%=LoopHelper.Index()%>">
        <h3><%:review.Title%></h3>                      
    </div>
 <%} %>

I've written some helper methods to enable this:

public static class LoopHelper {
    public static int Index() {
        return (int)HttpContext.Current.Items["LoopHelper_Index"];
    }       
}

public static class LoopHelperExtensions {
    public static IEnumerable<T> WithIndex<T>(this IEnumerable<T> that) {
        return new EnumerableWithIndex<T>(that);
    }

    public class EnumerableWithIndex<T> : IEnumerable<T> {
        public IEnumerable<T> Enumerable;

        public EnumerableWithIndex(IEnumerable<T> enumerable) {
            Enumerable = enumerable;
        }

        public IEnumerator<T> GetEnumerator() {
            for (int i = 0; i < Enumerable.Count(); i++) {
                HttpContext.Current.Items["LoopHelper_Index"] = i;
                yield return Enumerable.ElementAt(i);
            }
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
    }

In a non-web environment you could use a static instead of HttpContext.Current.Items.

This is essentially a global variable, and so you cannot have more than one WithIndex loop nested, but that is not a major problem in this use case.

mike nelson
  • 18,814
  • 13
  • 59
  • 66
0

This doesn't answer your specific question, but it DOES provide you with a solution to your problem: use a for loop to run through the object collection. then you will have the current index you are working on.

// Untested
for (int i = 0; i < collection.Count; i++)
{
    Console.WriteLine("My index is " + i);
}
BKSpurgeon
  • 24,945
  • 9
  • 86
  • 68
-3

i want to discuss this question more theoretically (since it has already enough practical answers)

.net has a very nice abstraction model for groups of data (a.k.a. collections)

  • At the very top, and the most abstract, you have an IEnumerable it's just a group of data that you can enumerate. It doesn't matter HOW you enumerate, it's just that you can enumerate some data. And that enumeration is done by a completely different object, an IEnumerator

these interfaces are defined is as follows:

//
// Summary:
//     Exposes an enumerator, which supports a simple iteration over a non-generic collection.
public interface IEnumerable
{
    //
    // Summary:
    //     Returns an enumerator that iterates through a collection.
    //
    // Returns:
    //     An System.Collections.IEnumerator object that can be used to iterate through
    //     the collection.
    IEnumerator GetEnumerator();
}

//
// Summary:
//     Supports a simple iteration over a non-generic collection.
public interface IEnumerator
{
    //
    // Summary:
    //     Gets the element in the collection at the current position of the enumerator.
    //
    // Returns:
    //     The element in the collection at the current position of the enumerator.
    object Current { get; }

    //
    // Summary:
    //     Advances the enumerator to the next element of the collection.
    //
    // Returns:
    //     true if the enumerator was successfully advanced to the next element; false if
    //     the enumerator has passed the end of the collection.
    //
    // Exceptions:
    //   T:System.InvalidOperationException:
    //     The collection was modified after the enumerator was created.
    bool MoveNext();
    //
    // Summary:
    //     Sets the enumerator to its initial position, which is before the first element
    //     in the collection.
    //
    // Exceptions:
    //   T:System.InvalidOperationException:
    //     The collection was modified after the enumerator was created.
    void Reset();
}
  • as you might have noticed, the IEnumerator interface doesn't "know" what an index is, it just knows what element it's currently pointing to, and how to move to the next one.

  • now here is the trick: foreach considers every input collection an IEnumerable, even if it is a more concrete implementation like an IList<T> (which inherits from IEnumerable), it will only see the abstract interface IEnumerable.

  • what foreach is actually doing, is calling GetEnumerator on the collection, and calling MoveNext until it returns false.

  • so here is the problem, you want to define a concrete concept "Indices" on an abstract concept "Enumerables", the built in foreach construct doesn't give you that option, so your only way is to define it yourself, either by what you are doing originally (creating a counter manually) or just use an implementation of IEnumerator that recognizes indices AND implement a foreach construct that recognizes that custom implementation.

personally i would create an extension method like this

public static class Ext
{
    public static void FE<T>(this IEnumerable<T> l, Action<int, T> act)
    {
        int counter = 0;
        foreach (var item in l)
        {
            act(counter, item);
            counter++;
        }
    }
}

and use it like this

var x = new List<string>() { "hello", "world" };
x.FE((ind, ele) =>
{
    Console.WriteLine($"{ind}: {ele}");
});

this also avoids any unnecessary allocations seen in other answers.

bigworld12
  • 794
  • 1
  • 8
  • 30