Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I run into this often during programming where I want to have a loop count index inside of a foreach and have to create an integer, use it, increment, etc. Wouldn't it be a good idea if there was a keyword introduced that was the loop count inside of a foreach? It could also be used in other loops as well.

Does this go against the use of keywords seeing as how the compiler would not allow this keyword used anywhere but in a loop construct?

share|improve this question
7  
You can do it yourself with an extension method, see the answer from Dan Finch: stackoverflow.com/a/521894/866172 (not the best rated answer, but I think it's the "cleaner" one) –  Jalayn Jun 14 '12 at 12:55
    
Perl and stuff like $_ comes to mind. I hate that stuff. –  Yam Marcovic Jun 14 '12 at 13:23
2  
From what I know about C#, it has many context-based keywords, so this wouldn't "go against the use of keywords". As pointed out in an answer below however, you probably just want to use a for () loop. –  Craige Jun 14 '12 at 13:58
    
@Jalayn Please post that as an answer. It is one of the best approaches. –  Monster Truck Jun 14 '12 at 14:08
    
@MonsterTruck: I don't think he should. The real solution would be to migrate this question to SO and close it as a duplicate of the question Jalayn links to. –  Brian Jun 14 '12 at 15:50

7 Answers 7

If you need a loop count inside a foreach loop why don't you just use a regular for loop. The foreach loop was intended to make specific uses of for loops simpler. It sounds like you have a situation where the simplicity of the foreach is no longer beneficial.

share|improve this answer
1  
+1 - good point. It's easy enough to use IEnumerable.Count or object.length with a regular for loop to avoid any problems with figuring out the number of elements in the object. –  GlenH7 Jun 14 '12 at 13:47
11  
@GlenH7: Depending on the the implementation, IEnumerable.Count could be expensive (or impossible, if it's a once only enumeration). You need to know what the underlying source is before you could safely do that. –  Binary Worrier Jun 14 '12 at 13:56
2  
-1: Bill Wagner in More Effective C# describes why one should always stick to foreach over for (int i = 0…). He has written a couple of pages but I can summarise in two words --compiler optimisation on iteration. Ok that wasn't two words. –  Monster Truck Jun 14 '12 at 14:05
12  
@MonsterTruck: whatever Bill Wagner wrote, I have seen enough situations like the one described by the OP, where a for loop gives better readable code (and theoretical compiler optimization is often premature optimization). –  Doc Brown Jun 14 '12 at 14:22
1  
@DocBrown This is not as simple as premature optimisation. I have myself identified bottlenecks in the past and fixed them using this approach (but I'll admit I was dealing with thousands of objects in the collection). Hope to post a working example soon. Meanwhile, here is Jon Skeet. [He says performance improvement won't be significant but that depends much on the collection and the number of objects]. –  Monster Truck Jun 14 '12 at 15:03

You can use anonymous types like this

foreach (var item in items.Select((v, i) => new { Value = v, Index = i }))
{
    Console.WriteLine(String.Format("Item value is {0} and index is {1}.", item.Value, item.Index));
}

This is similar to Python's enumerate function

for i, v in enumerate(items):
    print v, i
share|improve this answer
    
Oh, that is interesting. Thanks. –  Justin Jun 14 '12 at 13:10
    
+1 Oh... light bulb. I like that approach. Why have I never thought of it before? –  Phil Jun 14 '12 at 15:35
11  
Whoever prefers this in C# over a classical for loop clearly has a weird opinion on readability. This may be a neat trick but I wouldn't allow something like that in production quality code. It's much noisier than a classical for loop and cannot be understood as fast. –  Falcon Jun 14 '12 at 17:31
4  
@Falcon, this is an valid alternative IF YOU CAN'T USE an old fashion for loop (which needs an count). That's a few object's collections which I had to work around... –  Fabricio Araujo Jun 14 '12 at 18:42
4  
@FabricioAraujo: Surely C# for loops don't require a count. As far as I know they are just the same as C's for loops, which means you can use any boolean value to end the loop. Such as a check for the end of the enumeration when MoveNext returns false. –  Zan Lynx Jun 14 '12 at 20:16

I may be wrong about this, but I always thought that the main point of the foreach loop was to simplify iteration from the STL days of C++ i.e.

for(std::stltype<typename>::iterator iter = stl_type_instance.begin(); iter != stl_type_instance.end(); iter++)
{
   //dereference iter to use each object.
}

compare this to .NET's use of IEnumerable in the foreach

foreach(TypeName instance in DescendentOfIEnumerable)
{
   //use instance to use the object.
}

the latter is much simpler and avoids many of the old pitfalls. In addition, they seem to follow almost identical rules. For instance you can't change the the IEnumerable contents while inside the loop (which makes much more sense if you think of it the STL way). However, the for loop often has a different logical purpose than iteration.

share|improve this answer
4  
+1: few people remember that foreach is basically syntactic sugar over the iterator pattern. –  Steve Evers Jun 14 '12 at 13:36
1  
Well there are some differences; pointer manipulation where present in .NET is hidden pretty deeply from the programmer, but you could write a for loop that looked very much like the C++ example: for(IEnumerator e=collection.GetEnumerator;e.MoveNext();) { ... } –  KeithS Jun 14 '12 at 16:34
    
@KeithS, not if you realize that everything you touch in .NET that isn't a structured type IS A POINTER, just with different syntax (. instead of ->). In fact, passing a reference type to a method is the same as passing it as a pointer and passing it by reference is passing it as a double pointer. Same thing. At least, that is the way a person who's native language is C++ thinks about it. Sort of like, you learn Spanish in school by thinking about how the language is syntactically related to your own native language. –  Jonathan Henson Jun 14 '12 at 19:02
    
*value type not structured type. sorry. –  Jonathan Henson Jun 14 '12 at 23:04

I'm just adding Dan Finch's answer here, as requested.

Don't give me points, give points to Dan Finch :-)

The solution is to write the following generic extension method:

public static void Each<T>( this IEnumerable<T> ie, Action<T, int> action )
{
    var i = 0;
    foreach ( var e in ie ) action( e, i++ );
}

Which is used like so:

var strings = new List<string>();
strings.Each( ( str, n ) =>
{
    // hooray
} );
share|improve this answer
2  
That's pretty clever, but I think just using a normal for is more "readable", especially if down the road someone who ends up maintaining the code may not be much of an ace in .NET and not too familiar with the concept of extension methods. I'm still grabbing this little bit of code though. :) –  MetalMikester Jun 14 '12 at 15:12
    
Could argue either side of this, and the original question - I agree with the posters intent, there are cases where foreach reads better but an index is needed, yet I am always adverse to adding more syntactic sugar to a language if it isn't badly needed - I have exactly the same solution in my own code with a different name - strings.ApplyIndexed<T>(......) –  Mark Mullin Jun 14 '12 at 16:29
    
I agree with Mark Mullin, you can argue either side. I thought it was a pretty clever use of extension methods and it fitted the question so I shared it. –  Jalayn Jun 14 '12 at 16:56

If the collection in question is an IList<T>, you can simply use for with indexing:

for (int i = 0; i < collection.Count; i++)
{
    var item = collection[i];
    // …
}

If not, then you could use Select(), it has an overload that gives you the index.

If that's also not suitable, I think maintaining that index manually is simple enough, it's just two very short lines of code. Creating a keyword specifically for this would be an overkill.

int i = 0;
foreach (var item in collection)
{
    // …
    i++;
}
share|improve this answer
    
+1, also, if you are using an index exactly once inside the loop, you could do something like foo(++i) or foo(i++) depending on which index is needed. –  Job Jun 15 '12 at 3:51

If all you know is that the collection is an IEnumerable, but need to keep track of how many elements you have processed so far (and thus the total when you're done), you can add a couple lines to a basic for loop:

var coll = GetMyCollectionAsAnIEnumerable();
var idx = 0;
for(var e = coll.GetEnumerator(); e.MoveNext(); idx++)
{
   var elem = e.Current;

   //use elem and idx as you please
}

You can also add an incremented index variable to a foreach:

var i=0;
foreach(var elem in coll)
{
   //do your thing, then...
   i++;
}

If you want to make this look more elegant, you can define an extension method or two to "hide" these details:

public static void ForEach<T>(this IEnumerable<T> input, Action<T> action)
{
    foreach(T elem in input)
        action(elem);
}

public static void ForEach<T>(this IEnumerable<T> input, Action<T, int> action)
{
    var idx = 0;
    foreach(T elem in input)
        action(elem, idx++); //post-increment happens after parameter-passing
}

//usage of the index-supporting method
coll.ForEach((e, i)=>Console.WriteLine("Element " + (i+1) + ": " + e.ToString()));
share|improve this answer

Scoping also works if you want to keep the block clean of collisions with other names...

{ int index = 0; foreach(var el in List) { Console.WriteLine(el + " @ " + index++); } }
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.