164

Is there a C# equivalent of Python's enumerate() and Ruby's each_with_index?

Blorgbeard
  • 93,378
  • 43
  • 217
  • 263
Ken
  • 4,754
  • 6
  • 27
  • 25
  • If you're using LINQ, there are overrides of the various functions that allow for enumeration. Otherwise, you're usually stuck using a variable that you increment yourself. – GWLlosa Feb 06 '09 at 19:03
  • 1
    Can we update this question to C# 7.0 where there are tuples now? I wonder how a solution would look using tuples. – Hendrik Wiese Mar 13 '17 at 08:57
  • Isn"t that a feature of `foreach` that you can process each element absolute decoupled from its position in the list? – Konstantin A. Magg Apr 09 '18 at 11:21

10 Answers10

268

I keep this extension method around for this:

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

And use it like so:

var strings = new List<string>();
strings.Each((str, n) =>
{
    // hooray
});

Or to allow for break-like behaviour:

public static bool Each<T>(this IEnumerable<T> ie, Func<T, int, bool> action)
{
    int i = 0;
    foreach (T e in ie) if (!action(e, i++)) return false;
    return true;
}

var strings = new List<string>() { "a", "b", "c" };

bool iteratedAll = strings.Each ((str, n)) =>
{
    if (str == "b") return false;
    return true;
});
AustinWBryan
  • 2,968
  • 3
  • 17
  • 35
Dan
  • 3,119
  • 1
  • 14
  • 13
230

You can do the following

foreach (var it in someCollection.Select((x, i) => new { Value = x, Index = i }) )
{
   if (it.Index > SomeNumber) //      
}

This will create an anonymous type value for every entry in the collection. It will have two properties

  • Value: with the original value in the collection
  • Index: with the index within the collection
vzwick
  • 10,424
  • 5
  • 39
  • 60
JaredPar
  • 673,544
  • 139
  • 1,186
  • 1,421
  • 19
    Clever, but it's like scratching your left ear with your right hand. I guess I'll just keep the index myself, so I don't confuse future maintainers. – Ken Feb 06 '09 at 19:32
  • 1
    A for effort but F for general readability and maintenance. Sorry. – Neil N Feb 06 '09 at 19:52
  • 41
    @Neil, I'm amazed that people think this is a maintenence problem. This overload of Select (and other LINQ methods) was provided for the complete purpose of doing operations like this. – JaredPar Feb 06 '09 at 19:57
  • Very clever. For small n, this would suit the job nicely. Looks pretty readable to me. – spoulson Feb 06 '09 at 19:58
  • 4
    I see no issues with maintenance. If a future maintainer is incapable of going to the MSDN documentation and looking up the overloads to the Select method, that is their own problem. Worried about the variable names? Just do: (Value, Index) => select new { Value, Index } for the lambda. – Joshua Rodgers Jan 21 '11 at 14:49
  • 2
    I see no maintenance issues other than possibly giving x,i more useful names. They were obviously left vague here to be renamed to something appropriate when the code is inserted in the desired spot. If this type of code is unreadable to you I'd just forgo attempting any truly terse languages such as C++ or F#... – Dave Jellison Sep 07 '11 at 18:51
  • Compared to PHP's foreach($listvar as $index=>$val) it is clunky, but it's more flexible. Saying this is a maintenance problem is like saying the construct foreach(array_keys($array) as $val) is a maintenance problem... –  Mar 14 '12 at 20:03
  • 2
    This is clearly worse to the classical for loop. Because it's much more noisy. More (curly) brackets. More text to read. Harder to read and understand than the classical for loop by far. – Falcon Jun 14 '12 at 17:35
  • 1
    @Falcon the OP did not ask for the easiest to read solution, they asked for the closest equivalent to a construct from a different language which my answer represents – JaredPar Jun 14 '12 at 22:29
  • 2
    There's no point to using a very weird foreach instead of the usual for loop. Everyone that fails to see that's a maintenance issue should read ancient and grammatically correct English; believe me, convention helps. (also: more characters and less performance) – Lodewijk Jun 22 '14 at 20:23
  • 9
    @Lodewijk Without a backing collection, `IEnumerable.ElementAt(i)` is O(n) (see [Schlemiel the Painter](https://en.wikipedia.org/wiki/Schlemiel_the_Painter%27s_algorithm#Schlemiel_the_Painter.27s_algorithm)). And what if you have a lazy enumerable that's expensive to evaluate and contains a huge number of records? With a for loop, you have to wait for `IEnumerable.Count()` to return before you can start processing the records. A for loop is generally not appropriate for use with `IEnumerable`. – piedar Aug 04 '14 at 19:01
  • 1
    I think that's a surprisingly good point, but highly dependent on the situation. I would fully agree with you if it weren't so extremely rare that there isn't O(1) retrieval. I'll add to that that O(n) conversion to O(1) retrieval is still ultimately O(1). And in the normal situation (arrays, for example) foreach creates more assembly code than a normal "for" loop. In those special cases where it is better, do it with a foreach :). It's more functional, too, which is good. – Lodewijk Aug 04 '14 at 19:59
  • 5
    This can now get a bit shorter when using a C# 7 ValueTuple: `foreach (var (x, i) in someCollection.Select((x, i) => (x, i)) ) { ... }` – FernAndr Sep 17 '19 at 12:20
  • I've been using C# for almost 2 decades and the first time I made use of this was yesterday. Thanks, Jared. This will certainly come in handy. – vargonian Feb 12 '21 at 22:35
67

The C# foreach doesn't have a built in index. You'll need to add an integer outside the foreach loop and increment it each time.

int i = -1;
foreach (Widget w in widgets)
{
   i++;
   // do something
}

Alternatively, you could use a standard for loop as follows:

for (int i = 0; i < widgets.Length; i++)
{
   w = widgets[i];
   // do something
}
David Morton
  • 15,747
  • 2
  • 60
  • 72
  • 18
    I think you should initialize i to -1 and increment it at the beginning of the loop body to make sure that a "continue" statement doesn't cause problems. – Tamas Czinege Feb 06 '09 at 19:11
  • 7
    @DrJokepu why don't simply keep i = 0 and increment it before the closing bracket of the foreach statement? Initializing with something != 0 triggers the attention when you later browse the code... – Adi Aug 23 '12 at 09:32
  • worked in javascript – Taufik Nurhidayat Jan 01 '21 at 11:05
16

I like being able to use foreach, so I made an extension method and a structure:

public struct EnumeratedInstance<T>
{
    public long cnt;
    public T item;
}

public static IEnumerable<EnumeratedInstance<T>> Enumerate<T>(this IEnumerable<T> collection)
{
    long counter = 0;
    foreach (var item in collection)
    {
        yield return new EnumeratedInstance<T>
        {
            cnt = counter,
            item = item
        };
        counter++;
    }
}

and an example use:

foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
    Console.WriteLine(ii.item + ii.cnt);
}

One nice thing is that if you are used to the Python syntax, you can still use it:

foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))
obsoleter
  • 355
  • 2
  • 9
Daniel K
  • 877
  • 5
  • 12
15

Aside from the LINQ answers already given, I have a "SmartEnumerable" class which allows you to get the index and the "first/last"-ness. It's a bit ugly in terms of syntax, but you may find it useful.

We can probably improve the type inference using a static method in a nongeneric type, and implicit typing will help too.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • 2
    Great! These small little helper properties (first/last/index) should be included in the standard .net framework! – Philip Daubmeier Apr 19 '10 at 16:08
  • It is great, I just dislike its long and non descriptive name – Arek Bal Oct 22 '15 at 19:02
  • The link appears to to be dead. The best links I can find are [this](https://jonskeet.uk/csharp/miscutil/) (for the encompassing library) and [this](https://codeblog.jonskeet.uk/2007/07/27/smart-enumerations/) for Jon's blog discussing it. – Robin Macharg Apr 16 '19 at 09:28
  • @RobinMacharg: I've edited the link, thanks. – Jon Skeet Apr 16 '19 at 09:32
6

My solution involves a simple Pair class I created for general utility, and which is operationally essentially the same as the framework class KeyValuePair. Then I created a couple extension functions for IEnumerable called Ordinate (from the set theory term "ordinal").

These functions will return for each item a Pair object containing the index, and the item itself.

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs)
{
    return lhs.Ordinate(0);
}

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs, Int32 initial)
{
    Int32 index = initial - 1;

    return lhs.Select(x => new Pair<Int32, X>(++index, x));
}
Chris Ammerman
  • 14,171
  • 8
  • 37
  • 41
3

No, there is not.

As other people have shown, there are ways to simulate Ruby's behavior. But it is possible to have a type that implements IEnumerable that does not expose an index.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Darryl Braaten
  • 5,082
  • 4
  • 33
  • 49
1

This is your collection

var values = new[] {6, 2, 8, 45, 9, 3, 0};

Make a range of indexes for this collection

var indexes = Enumerable.Range(0, values.Length).ToList();

Use the range to iterate with index

indexes.ForEach(i => values[i] += i);
indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
vonWippersnap
  • 423
  • 3
  • 8
1

I just figured out interesting solution:

public class DepthAware<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> source;

    public DepthAware(IEnumerable<T> source)
    {
        this.source = source;
        this.Depth = 0;
    }

    public int Depth { get; private set; }

    private IEnumerable<T> GetItems()
    {
        foreach (var item in source)
        {
            yield return item;
            ++this.Depth;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return GetItems().GetEnumerator();
    }

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

// Generic type leverage and extension invoking
public static class DepthAware
{
    public static DepthAware<T> AsDepthAware<T>(this IEnumerable<T> source)
    {
        return new DepthAware<T>(source);
    }

    public static DepthAware<T> New<T>(IEnumerable<T> source)
    {
        return new DepthAware<T>(source);
    }
}

Usage:

var chars = new[] {'a', 'b', 'c', 'd', 'e', 'f', 'g'}.AsDepthAware();

foreach (var item in chars)
{
    Console.WriteLine("Char: {0}, depth: {1}", item, chars.Depth);
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Pz.
  • 1,009
  • 9
  • 14
  • 2
    Resurrecting a zombie since I just needed this: this will behave confusingly if the enumerable is iterated more than once. – millimoose Jun 20 '14 at 14:51
  • You are right. If I were to implement this today, I'd definitely go with the accepted answer. – Pz. Nov 04 '19 at 11:51
0

It depends on the class you are using.

Dictionary<(Of <(TKey, TValue>)>) Class For Example Support This

The Dictionary<(Of <(TKey, TValue>)>) generic class provides a mapping from a set of keys to a set of values.

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<(Of <(TKey, TValue>)>) structure representing a value and its key. The order in which the items are returned is undefined.

foreach (KeyValuePair kvp in myDictionary) {...}

VBNight
  • 1,734
  • 14
  • 12