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

Счетчик в цикле foreach в С#

Работа foreach: Как я знаю,

foreach - это цикл, который выполняет итерацию через набор или массив по один, начиная с индекса 0 до последний элемент коллекции.

Итак, если у меня есть n элементов в массиве.

foreach (var item in arr)
{

}  

то, In, 1-я итерация, item = arr [0];
затем, во втором, item = arr [1];
.
.
.
в последнем (n-м), item = arr [n-1];

Заключение: от работы кажется, что на каждой итерации он знает, какое значение следует брать из массива или он знает индекс элемента, который нужно взять из массива.

Теперь мой вопрос: Как я могу получить индекс элемента без использования новой переменной?

foreach (string item in mylist)
{
   if (item == "myitem")
   {
       // get index of item
       break;
   }
}
4b9b3361

Ответ 1

Это зависит от того, что вы подразумеваете под "этим". Итератор знает, какой индекс он достиг, да - в случае List<T> или массива. Но нет общего индекса внутри IEnumerator<T>. Является ли оно итерированием по индексированной коллекции или нет, зависит от реализации. Множество коллекций не поддерживает прямую индексацию.

(Фактически, foreach не всегда использует итератор вообще. Если тип времени компиляции коллекции является массивом, компилятор будет перебирать его с помощью array[0], array[1] и т.д. Подобным образом коллекция может иметь метод под названием GetEnumerator(), который возвращает тип с соответствующими членами, но без какой-либо реализации IEnumerable/IEnumerator.)

Параметры для поддержания индекса:

  • Используйте цикл for
  • Используйте отдельную переменную
  • Используйте проекцию, которая проектирует каждый элемент к паре индексов/значений, например.

     foreach (var x in list.Select((value, index) => new { value, index }))
     {
         // Use x.value and x.index in here
     }
    
  • Используйте мой SmartEnumerable класс, который немного похож на предыдущий вариант

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

Ответ 2

Используйте for вместо foreach. foreach не раскрывает свои внутренние операции, он перечисляет все, что есть IEnumerable (которое вообще не должно иметь индекс).

for (int i=0; i<arr.Length; i++)
{
    ...
}

Кроме того, если вы пытаетесь найти индекс определенного элемента в списке, вам не нужно его повторять самостоятельно. Вместо этого используйте Array.IndexOf(item).

Ответ 3

Ваше понимание foreach является неполным.

Он работает с любым типом, который предоставляет IEnumerable (или реализует метод GetEnumerable) и использует возвращенный IEnumerator для перебора элементов в коллекции.

Как это делает Enumerator (с помощью оператора index, yield или magic), является детальностью реализации.

Чтобы достичь желаемого, вы должны использовать цикл for:

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

Примечание:

Получение количества элементов в списке несколько отличается в зависимости от типа списка

For Collections: Use Count   [property]
For Arrays:      Use Length  [property]
For IEnumerable: Use Count() [Linq method]

Ответ 4

Или даже проще, если вы не хотите использовать много linq и по какой-то причине не хотите использовать цикл for.

int i = 0;
foreach(var x in arr)
{
   //Do some stuff
   i++;
}

Ответ 5

Возможно, бессмысленно, но...

foreach (var item in yourList.Select((Value, Index) => new { Value, Index }))
{
    Console.WriteLine("Value=" + item.Value + ", Index=" + item.Index);
}

Ответ 6

Это верно только в том случае, если вы выполняете итерацию через массив; что делать, если вы повторяете через другой тип коллекции, не имеющей понятия доступа к индексу? В случае массива самый простой способ сохранить индекс - просто использовать ваниль для цикла.

Ответ 7

Не все коллекции имеют индексы. Например, я могу использовать Dictionary с foreach (и повторять все ключи и значения), но я не могу писать get для отдельных элементов с помощью dictionary[0], dictionary[1] и т.д.

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

Ответ 8

Последовательность, повторяющаяся в цикле foreach, может не поддерживать индексирование или знать такую ​​концепцию, ей просто нужно реализовать метод GetEnumerator, который возвращает объект, который, как минимум, имеет интерфейс IEnumerator, хотя имплантация не требуется. Если вы знаете, что то, что вы итерации, поддерживает индексирование, и вам нужен индекс, я предлагаю вместо этого использовать цикл for.

Примерный класс, который можно использовать в foreach:

    class Foo {

        public iterator GetEnumerator() {
            return new iterator();
        }

        public class iterator {
            public Bar Current {
                get{magic}
            }

            public bool MoveNext() {
                incantation
            }
        }
    }

Ответ 9

Из MSDN:

Оператор foreach повторяет группу встроенных операторов для каждого элемент в массиве или объекте коллекции, которая реализует System.Collections.IEnumerable или System.Collections.Generic.IEnumerable(Из T).

Итак, это не обязательно Array. Это может быть даже ленивая коллекция, не имеющая представления о количестве элементов в коллекции.

Ответ 10

Без пользовательской версии Foreach:

datas.Where((data, index) =>
{
    //Your Logic
    return false;
}).Any();

В некотором простом случае мой способ использует where + false + any.
Это немного больше, чем foreach + select((data,index)=>new{data,index}) и без специального метода Foreach.

MyLogic:

  • тело оператора use запускает вашу логику.
  • потому что возвращают false, количество новых перечисляемых данных равно нулю.
  • используйте Any(), чтобы запустить yeild.

Контрольный тестовый код

[RPlotExporter, RankColumn]
public class BenchmarkTest
{
    public static IEnumerable<dynamic> TestDatas = Enumerable.Range(1, 10).Select((data, index) => $"item_no_{index}");

    [Benchmark]
    public static void ToArrayAndFor()
    {
        var datats = TestDatas.ToArray();
        for (int index = 0; index < datats.Length; index++)
        {
            var result = $"{datats[index]}{index}";
        }
    }

    [Benchmark]
    public static void IEnumrableAndForach()
    {
        var index = 0;
        foreach (var item in TestDatas)
        {
            index++;
            var result = $"{item}{index}";
        }
    }

    [Benchmark]
    public static void LinqSelectForach()
    {
        foreach (var item in TestDatas.Select((data, index) => new { index, data }))
        {
            var result = $"{item.data}{item.index}";
        }
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToList()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToList();
    }

    [Benchmark]
    public static void LinqSelectStatementBodyToArray()
    {
        TestDatas.Select((data, index) =>
        {
            var result = $"{data}{index}";
            return true;
        }).ToArray();
    }

    [Benchmark]
    public static void LinqWhereStatementBodyAny()
    {
        TestDatas.Where((data, index) =>
        {
            var result = $"{data}{index}";
            return false;
        }).Any();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<BenchmarkTest>();

        System.Console.Read();
    }
}

Результат теста:

                         Method |     Mean |     Error |    StdDev | Rank |
------------------------------- |---------:|----------:|----------:|-----:|
                  ToArrayAndFor | 4.027 us | 0.0797 us | 0.1241 us |    4 |
            IEnumrableAndForach | 3.494 us | 0.0321 us | 0.0285 us |    1 |
               LinqSelectForach | 3.842 us | 0.0503 us | 0.0471 us |    3 |
  LinqSelectStatementBodyToList | 3.822 us | 0.0416 us | 0.0389 us |    3 |
 LinqSelectStatementBodyToArray | 3.857 us | 0.0764 us | 0.0785 us |    3 |
      LinqWhereStatementBodyAny | 3.643 us | 0.0693 us | 0.0712 us |    2 |