31

How do I get the key of the current element in a foreach loop in C#?

For example:

PHP

foreach ($array as $key => $value)
{
    echo("$value is assigned to key: $key");
}

What I'm trying to do in C#:

int[] values = { 5, 14, 29, 49, 99, 150, 999 };

foreach (int val in values)
{
    if(search <= val && !stop)
    {
         // Set key to a variable
    }
}

9 Answers 9

25

Grauenwolf's way is the most straightforward and performant way of doing this with an array:

Either use a for loop or create a temp variable that you increment on each pass.

Which would of course look like this:

int[] values = { 5, 14, 29, 49, 99, 150, 999 };

for (int key = 0; key < values.Length; ++key)
  if (search <= values[key] && !stop)
  {
    // set key to a variable
  }

With .NET 3.5 you can take a more functional approach as well, but it is a little more verbose at the site, and would likely rely on a couple support functions for visiting the elements in an IEnumerable. Overkill if this is all you need it for, but handy if you tend to do a lot of collection processing.

Sign up to request clarification or add additional context in comments.

2 Comments

"or create a temp variable that you increment on each pass" as far as I remember, there is no guarantee that foreach will loop over your collection in an ascending (or descending) order, only that it will stop at every element at exactly once, therefor if you are using an external value, your solution might- or might not be valid based on the implementation. Normally it will give you the desired result, but i.e. a common optimization is to parse an array in descending order (it takes one less machine instruction than ascending order per cycle).
I think that depends on the type of enumerable you're iterating over. If it's an array, I'd think order would be guaranteed.
23

If you want to get at the key (read: index) then you'd have to use a for loop. If you actually want to have a collection that holds keys/values then I'd consider using a HashTable or a Dictionary (if you want to use Generics).

Dictionary<int, string> items = new  Dictionary<int, string>();

foreach (int key in items.Keys)
{
  Console.WriteLine("Key: {0} has value: {1}", key, items[key]);
}

Hope that helps, Tyler

1 Comment

It would be much more performant to do foreach(KeyValuePair<int, string> pair in items) and then reference pair.Key and pair.Value, rather than doing a lookup in each iteration.
11

With DictionaryEntry and KeyValuePair:

Based on
MSDN

IDictionary<string,string> openWith = new Dictionary<string,string>()
{
   { "txt", "notepad.exe" }
   { "bmp", "paint.exe" }
   { "rtf", "wordpad.exe" }
};

foreach (DictionaryEntry de in openWith)
{
    Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}

// also

foreach (KeyValuePair<string,string> de in openWith)
{
    Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}

Releated SO question: KeyValuePair VS DictionaryEntry

Comments

4

Alas there is no built-in way to do this. Either use a for loop or create a temp variable that you increment on each pass.

Comments

3

I answered this in another version of this question:

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.

Obviously, 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.

How do you get the index of the current iteration of a foreach loop?

Comments

2

Actually you should use classic for (;;) loop if you want to loop through an array. But the similar functionality that you have achieved with your PHP code can be achieved in C# like this with a Dictionary:

Dictionary<int, int> values = new Dictionary<int, int>();
values[0] = 5;
values[1] = 14;
values[2] = 29;
values[3] = 49;
// whatever...

foreach (int key in values.Keys)
{
    Console.WriteLine("{0} is assigned to key: {1}", values[key], key);
}

1 Comment

It would be much more performant to do foreach(KeyValuePair<int, int> pair in values) and then reference pair.Key and pair.Value, rather than doing a lookup in each iteration.
0

You can implement this functionality yourself using an extension method. For example, here is an implementation of an extension method KeyValuePairs which works on lists:

public struct IndexValue<T> {
    public int Index {get; private set;}
    public T Value {get; private set;}
    public IndexValue(int index, T value) : this() {
        this.Index = index;
        this.Value = value;
    }
}

public static class EnumExtension
{
    public static IEnumerable<IndexValue<T>> KeyValuePairs<T>(this IList<T> list) {
        for (int i = 0; i < list.Count; i++)
            yield return new IndexValue<T>(i, list[i]);
    }
}

Comments

0

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;
    }

Comments

-10

myKey = Array.IndexOf(values, val);

2 Comments

That isn't a good idea. Array.IndexOf is basically a search with a worse case of O(n). Do that n times, can your total worse case becomes O(n^2). In layman's terms, an array of 100 items could take up to 10000 comparisons.
Efficiency aside, if the array has duplicated items you'll get the index of the first one, not necessarily the one you're on. Consider an array of { 5, 14, 5, 29, ... }. When 'val' is 5 you'll always get zero even if you're on the third element.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.