Подтвердить что ты не робот

С# новичок: узнайте индекс в блоке foreach

У меня есть блок foreach, где я хочу отображать для отслеживания-отладки значения индекса шага внутри foreach. Как новичок С# я делаю это следующим образом:

int i = 1;

foreach (x in y)
{
    ... do something ...
    WriteDebug("Step: "+i.ToString());
    i++;
}

Я задавался вопросом, есть ли способ получить значение индекса текущего шага без явного создания переменной для этой цели.

EDIT: Чтобы уточнить, я, очевидно, знаком с опцией цикла for, однако это не массив, который я просматриваю, а скорее неупорядоченная коллекция. Причина нумерации - только для того, чтобы показать прогресс на уровне отладки и ничего больше.

4b9b3361

Ответ 1

Нет, нет.

Это пример, когда вам лучше использовать базовый цикл

for(int i = 0; i < y.Count; i++)
{
}

а не a для каждого цикла

РЕДАКТИРОВАТЬ: в ответ на разъяснения адептов.

Если вы выполняете итерацию через счетчик без свойства размера (например, длина или количество), тогда ваш подход примерно так же ясен, как вы можете получить.

Второе редактирование
Учитывая меня, druthers я отвечу Marc, используя выбор, чтобы сделать это в эти дни.

Ответ 2

Вопреки нескольким другим ответам, я был бы счастлив смешивать foreach с счетчиком (в соответствии с кодом в вопросе). Это сохраняет возможность использовать IEnumerable[<T>] вместо того, чтобы требовать индексатора.

Но если вы хотите, в LINQ:

    foreach (var pair in y.Select((x,i) => new {Index = i,Value=x})) {
        Console.WriteLine(pair.Index + ": " + pair.Value);
    }

(подход счетчика в вопросе намного проще и эффективнее, но приведенное выше должно лучше сопоставляться с несколькими сценариями, такими как Parallel.ForEach).

Ответ 3

Нет, нет явного "счетчика" внутри цикла foreach.

То, что цикл foreach делает за крышками, создает IEnumerator, а затем циклически перебирает элементы один за другим, вызывая метод .MoveNext() в интерфейсе IEnumerator.

Там (к сожалению?) нет никакой переменной счетчика, отображаемой на интерфейсе IEnumerator - только методы .Reset() и .MoveNext() и свойство Current (возврат текущего элемента)

Марк

Ответ 4

Ваш подход примерно такой же ясный, как и он. Тем не менее, вы можете захотеть отметить, что часть я ++ на самом деле не связана с основной функциональностью цикла (без учета количества/длины/других параметров). Таким образом, вам может потребоваться переместить writeDebug и я ++ в отдельный метод/класс (updateProgress()) и просто вызвать это из цикла.

Ответ 5

A foreach использует интерфейс IEnumerator, который имеет свойства Current, MoveNext и Reset.

Текущая возвращает объект, в который включен Enumerator, MoveNext обновляет текущий до следующего объекта.

В foreach нет понятия индекса, и мы не будем уверены в порядке перечисления.

Вам придется либо применить к нему переменную, либо использовать цикл for вместо этого.

Я бы предпочел использовать for для lop вместо отслеживания этого с помощью переменной.

Ответ 6

Нет, нет способа получить это внутри цикла foreach. В этом случае вы должны использовать for-loop или, как вы упомянули, явно создать переменную для подсчета.

Ответ 7

Это зависит от фактического типа перечислителя, который вы зацикливаете. Однако многие коллекции имеют метод IndexOf

        ArrayList arrayList = new ArrayList();

        arrayList.Add("A");
        arrayList.Add("B");
        arrayList.Add("C");

        foreach (string item in arrayList)
        {
            int i = arrayList.IndexOf(item);
        }

Конечно, это не работает, если у вас есть дубликаты в списке. Это также не самое эффективное решение. Я бы придерживался вашего оригинального и просто сохранил переменную, чтобы отслеживать индекс.

Ответ 8

Я не знаю, что именно "y" в вашем примере, но, возможно, вы могли бы написать его следующим образом:

  foreach (var x in y.WithIndex())
  {
    WriteDebug(String.Format("Step: {0}", x.Index));
  }

При добавлении в проект следующего класса расширения:

  public static class Extensions
  {
    public static IEnumerable<IndexValuePair<T>> WithIndex<T>(this IEnumerable<T> source)
    {
      if (source == null) throw new ArgumentNullException("source");
      var position = 0;
      foreach (T value in source)
      {
        yield return new IndexValuePair<T>(position++, value);
      }
    }
  }

  public class IndexValuePair<T>
  {
    public IndexValuePair(Int32 index, T value)
    {
      this.index = index;
      this.value = value;
    }

    private readonly Int32 index;
    public Int32 Index
    {
      get { return index; }
    }

    private readonly T value;
    public T Value
    {
      get { return value; }
    }
  }

НТН, Деяна

Ответ 9

Если вам абсолютно необходим указатель, используйте вместо него традиционный цикл.

for (int i = 0; i < y.Count; i++)
{
    WriteDebug("Step: "+i.ToString());    
}

Ответ 10

Попробуй это:

foreach (var x in y)
{
    //... do something ...
    WriteDebug("Step: "Array.IndexOf(y,x).ToString());

}