Как получить ключ текущего элемента в цикле foreach в C#?
Например:
foreach ($array as $key => $value)
{
echo("$value is assigned to key: $key");
}
int[] values = { 5, 14, 29, 49, 99, 150, 999 };
foreach (int val in values)
{
if (search <= val && !stop)
{
// Set key to a variable
}
}





Увы, встроенного способа сделать это нет. Либо используйте цикл for, либо создайте временную переменную, которая увеличивается на каждом проходе.
myKey = Array.IndexOf(values, val);
Помимо эффективности, если в массиве есть повторяющиеся элементы, вы получите индекс первого, не обязательно того, который вы используете. Рассмотрим массив из {5, 14, 5, 29, ...}. Когда val равно 5, вы всегда получите ноль, даже если вы находитесь на третьем элементе.
Если вы хотите получить ключ (читайте: индекс), вам придется использовать цикл for. Если вы действительно хотите иметь коллекцию, содержащую ключи / значения, я бы подумал об использовании HashTable или Dictionary (если вы хотите использовать 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]);
}
Надеюсь, это поможет, Тайлер
Было бы намного эффективнее выполнить foreach (пара KeyValuePair <int, string> в элементах), а затем ссылаться на pair.Key и pair.Value, а не выполнять поиск на каждой итерации.
На самом деле вам следует использовать классический цикл for (;;), если вы хотите перебирать массив. Но аналогичная функциональность, которую вы достигли с помощью своего PHP-кода, может быть достигнута на C#, например, с помощью словаря:
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);
}
Было бы гораздо эффективнее выполнить foreach (пара KeyValuePair <int, int> в значениях), а затем ссылаться на pair.Key и pair.Value, а не выполнять поиск на каждой итерации.
Путь Грауэнвольфа - самый простой и эффективный способ сделать это с массивом:
Either use a for loop or create a temp variable that you increment on each pass.
Что, конечно, выглядело бы так:
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
}
С .NET 3.5 вы также можете использовать более функциональный подход, но он немного более подробный на сайте и, вероятно, будет полагаться на пару вспомогательные функции для посещение элементов в IEnumerable. Излишний, если это все, что вам нужно, но удобно, если вы склонны выполнять большую часть обработки коллекции.
Я думаю, это зависит от типа перечисляемого, который вы повторяете. Если это массив, я думаю, порядок будет гарантирован.
Я ответил на это в другой версии этого вопроса:
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() * CurrentCurrent 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.
Вот решение, которое я только что придумал для этой проблемы
Исходный код:
int index=0;
foreach (var item in enumerable)
{
blah(item, index); // some code that depends on the index
index++;
}
Обновленный код
enumerable.ForEach((item, index) => blah(item, index));
Метод расширения:
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;
}
Вы можете реализовать эту функцию самостоятельно, используя метод расширения. Например, вот реализация метода расширения KeyValuePairs, который работает со списками:
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]);
}
}
С помощью DictionaryEntry и KeyValuePair:
На основе
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);
}
Это плохая идея. Array.IndexOf - это в основном поиск с худшим случаем O (n). Сделайте это n раз, ваш общий худший случай станет O (n ^ 2). С точки зрения непрофессионала, массив из 100 элементов может потребовать до 10000 сравнений.