Как найти последний цикл в For Each (VB.NET)? - PullRequest
24 голосов
/ 18 декабря 2008

Как я могу определить, вхожу ли я в последний цикл оператора For Each в VB.NET?

Ответы [ 12 ]

53 голосов
/ 28 октября 2010

Обычно коллекции, в которых вы можете выполнить For Each для реализации интерфейса IEnumerator. Этот интерфейс имеет только два метода, MoveNext и Reset и одно свойство, Current.

Обычно, когда вы используете For Each в коллекции, она вызывает функцию MoveNext и считывает возвращаемое значение. Если возвращаемое значение равно True, это означает, что в коллекции есть действительный элемент и элемент возвращается через свойство Current. Если в коллекции больше нет элементов, функция MoveNext возвращает False и итерация завершается.

Из приведенного выше объяснения ясно, что For Each не отслеживает текущую позицию в коллекции, и поэтому ответ на ваш вопрос короткий Нет .

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

For Each item in Collection
    If item Is Collection.Last Then
        'do something with your last item'
    End If
Next
13 голосов
/ 18 декабря 2008

Вероятно, было бы проще использовать цикл For вместо ForEach. Но, аналогично, вы можете оставить счетчик внутри цикла ForEach и посмотреть, равен ли он yourCollection.Count - 1, тогда вы находитесь на последней итерации.

6 голосов
/ 18 декабря 2008

С foreach вы не можете знать это, пока не станет слишком поздно (т. Е. Вы не в курсе).

Обратите внимание, я предполагаю, что вы используете что-то, где у вас есть только интерфейс IEnumerable. Если у вас есть список, массив и т. Д., Следуйте другим ответам, в которых используется .Count или аналогичный, чтобы узнать, сколько элементов существует, и, таким образом, вы можете отслеживать, где находитесь в коллекции.

Однако, используя только IEnumerable / IEnumerator, невозможно точно узнать, есть ли их больше или нет, если вы используете foreach.

Если вам нужно это знать, используйте IEnumerable самостоятельно, что и делает foreach.

Приведенное ниже решение предназначено для C #, но его легко перевести на VB.NET:

.
List<Int32> nums = new List<Int32>();
nums.Add(1);
nums.Add(2);
nums.Add(3);

IEnumerator<Int32> enumerator = nums.GetEnumerator();
if (enumerator.MoveNext())
{
    // at least one value available
    while (true)
    {
        // make a copy of it
        Int32 current = enumerator.Current;

        // determine if it was the last value
        // if not, enumerator.Current is now the next value
        if (enumerator.MoveNext())
        {
            Console.Out.WriteLine("not last: " + current);
        }
        else
        {
            Console.Out.WriteLine("last: " + current);
            break;
        }
    }
}
enumerator.Dispose();

Будет напечатано:

not last: 1
not last: 2
last: 3

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

2 голосов
/ 18 декабря 2008

Краткий ответ: Вы не можете

Длинный ответ: в семантике оператора For Each нет ничего, что позволяло бы определить, выполняете ли вы первую, последнюю или любую конкретную итерацию.

For Each встроен в интерфейсы IEnumerable и IEnumerable <>, и его поведение зависит от реализации, которую вы вызываете. Это допустимо, хотя и сбивает с толку, для коллекции, которую вы повторяете, чтобы каждый раз возвращать элементы в другом порядке. К счастью, List <> этого не делает.

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

Проще было бы обнаружить первую итерацию (скажем, через логическое значение), а затем сделать что-то другое.

Пример (C #, но VB будет аналогичным):

StringBuilder result = new StringBuilder();
bool firstTime = true;
foreach(string s in names)
{
    if (!firstTime)
    {
        result.Append(", ");
    }

    result.Append(s);
    firstTime = false;
}
1 голос
/ 20 декабря 2013

этот пример кода может помочь

For Each item in Collection
  If ReferenceEquals(Collection.Item(Collection.Count - 1), item) Then
    'do something with your last item'
  End If
Next
1 голос
/ 28 февраля 2013

Я продолжаю возвращаться к этому посту, поэтому я решил сесть и подумать об этой проблеме, и я придумал это:

    For Each obj In myCollection
        Console.WriteLine("current object: {0}", obj.ToString)

        If Object.ReferenceEquals(obj, myCollection.Last()) Then
            Console.WriteLine("current object is the last object")
        End If
    Next

Вы можете даже сократить оператор If...Then...End If до одной строки, если хотите. Я не уверен, что вызов .Last() на каждой итерации сильно влияет на производительность, но вы всегда можете присвоить его переменной вне цикла, если это не дает вам спать по ночам.

1 голос
/ 18 декабря 2008

Используя стандартный цикл «Для каждого», вы не можете. Целью цикла «для каждого» является предоставление вам возможности сконцентрироваться на данных вместо основной коллекции.

1 голос
/ 18 декабря 2008

Было бы проще использовать цикл For вместо ForEach, однако вы могли бы сделать что-то вроде

If item.Equals(itemCollection(itemCollection.Count)) Then
    ...
End If

внутри вашего цикла ForEach ... Если объект правильно переопределил метод Equals.

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

Я не уверен, что это правильный синтаксис, я давно не пользовался VB.

1 голос
/ 18 декабря 2008

Проверьте, является ли элемент последним элементом контейнера.

Почему вы хотите это сделать?
Вы можете просто разместить инструкции после цикла. (Что вы выполняете на последнем элементе)

0 голосов
/ 10 января 2018

вот простая вещь, которую я не знаю, является ли она политкорректной, но она работает

for each item in listOfThings
   if(item = listOfThings.last)then 
       'you found the last loop
   end if
next 
...