Как узнать, что это последняя итерация цикла?

#c# #list #generics

#c# #Список #общие сведения

Вопрос:

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

 List<string> myList = new List<string>() {"are", "we", "there", "yet"};

foreach(string myString in myList) {
    // Is there a fancy way to find out here if this is the last time through?
}
  

Комментарии:

1. что вы пытаетесь сделать с последним элементом? Вы пытаетесь построить предложение и добавить знаки препинания в конце? Если это так, вы могли бы попробовать string.Join(" ", myList.ToArray()) "."

2. нашел решение для вас, ваааааай внизу…

Ответ №1:

Нет, для этого вам придется использовать обычный for(int i=0; i<myList.Length; i ) { ... } цикл.

Комментарии:

1. Спасибо, это был мой запасной вариант, но я хотел сначала убедиться, что я ничего не упустил.

Ответ №2:

Как насчет использования вместо цикла for?

 List<string> myList = new List<string>() {"are", "we", "there", "yet"};

for (var i=0; i<myList.Count; i  )
{
   var myString = myList[i];
   if (i==myList.Count-1)
   {
      // this is the last item in the list
   }
}
  

foreach полезно — но если вам нужно вести подсчет того, что вы делаете, или индексировать вещи по количеству, тогда просто вернитесь к старому доброму for циклу.

Ответ №3:

Есть два способа, которыми я бы это сделал.

Во-первых, с for циклом вместо foreach

 for(int i = 0; i < myList.Count; i  )
{
    string myString = myList[i];
    bool isLast = i == myList.Count - 1;

    ...
}
  

Или, если это необходимо для работы с перечислителями, измените порядок вещей. Обычно MoveNext выполняется как элемент управления циклом while, но если мы сделаем это прямо в начале цикла, мы можем использовать его возврат, чтобы определить, находимся ли мы в конце списка или нет.

 IEnumerator<string> enumerator = myList.GetEnumerator();
bool isLast = !enumerator.MoveNext();
while(!isLast)
{
    string myString = enumerator.Current;
    isLast = !enumerator.MoveNext();

    ...
}
  

Ответ №4:

Эффективного способа сделать это нет.

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

Ответ №5:

Ну … нет способа узнать это. Не так просто, как вы могли бы предположить. Структура данных списка — это просто способ упорядочить элементы один за другим. Но у вас нет способа сказать, является ли элемент последним элементом, просто используя foreach structure. Лучше всего использовать for structure со свойством count, чтобы узнать, попали ли вы в последний (или предыдущий) элемент.

 var length = list.Count;

for (var idx = 0; idx < list.Count; idx  )
{
    if (idx == (length - 1))
    {
        // The last item. Do something
    }
}
  

надеюсь, это поможет.

Ответ №6:

Нет, такого не существует, вам придется использовать счетчик, если вы хотите использовать foreach .

Ответ №7:

Используйте for operator вместо foreach

Ответ №8:

«Необычный» способ — поддерживать 1 элемент lookahead, но с какой стати вы этого хотите? Просто веду подсчет. Вот необычный способ. Нет счетчиков, нет проверки свойства Count. Все, что он использует, это перечислитель:

 using System;
using System.Collections.Generic;

namespace Sandbox
{
  class Program
  {

    enum ListPosition : byte
    {
      First     = 0x01       ,
      Only      = First|Last ,
      Middle    = 0x02       ,
      Last      = 0x04       ,
      Exhausted = 0x00       ,
    }

    private static void WalkList( List<int> numbers )
    {
      List<int>.Enumerator numberWalker = numbers.GetEnumerator();
      bool                 currFetched  = numberWalker.MoveNext();
      int                  currValue    = currFetched ? numberWalker.Current : default( int );
      bool                 nextFetched  = numberWalker.MoveNext();
      int                  nextValue    = nextFetched ? numberWalker.Current : default( int );
      ListPosition         position     ;

      if      (   currFetched amp;amp;   nextFetched ) position = ListPosition.First     ;
      else if (   currFetched amp;amp; ! nextFetched ) position = ListPosition.Only      ;
      else if ( ! currFetched                  ) position = ListPosition.Exhausted ;
      else throw new InvalidOperationException( "Reached Unreachable Code. Hmmm...that doesn't seem quite right" );

      while ( position != ListPosition.Exhausted )
      {
        string article = ( position==ListPosition.Middle?"a":"the" );

        Console.WriteLine( "  {0} is {1} {2} item in the list" , currValue , article , position );

        currFetched = nextFetched ;
        currValue   = nextValue   ;

        nextFetched = numberWalker.MoveNext()                         ;
        nextValue   = nextFetched?numberWalker.Current:default( int ) ;

        if      (   currFetched amp;amp;   nextFetched ) position = ListPosition.Middle    ;
        else if (   currFetched amp;amp; ! nextFetched ) position = ListPosition.Last      ;
        else if ( ! currFetched                  ) position = ListPosition.Exhausted ;
        else throw new InvalidOperationException( "Reached Unreachable Code. Hmmm...that doesn't seem quite right" );

      }

      Console.WriteLine() ;
      return ;
    }

    static void Main( string[] args )
    {
      List<int> list1 = new List<int>( new []{ 1 ,             } ) ;
      List<int> list2 = new List<int>( new []{ 1 , 2 ,         } ) ;
      List<int> list3 = new List<int>( new []{ 1 , 2 , 3 ,     } ) ;
      List<int> list4 = new List<int>( new []{ 1 , 2 , 3 , 4 , } ) ;

      Console.WriteLine( "List 1:" ) ; WalkList( list1 ) ;
      Console.WriteLine( "List 2:" ) ; WalkList( list2 ) ;
      Console.WriteLine( "List 3:" ) ; WalkList( list3 ) ;
      Console.WriteLine( "List 4:" ) ; WalkList( list4 ) ;

      return ;
    }

  }
}
  

Ответ №9:

Зависит от вашего определения «необычного». Это может соответствовать:

 if (myList.Count > 0)
{
    myList.Take(myList.Count - 1)).ForEach(myString => doSomething(myString));
    doSomethingElse(myList.Last());
}
  

Мне это кажется близким к тому, что вы ищете. Обратите внимание, что это не очень высокопроизводительно, но коротко и довольно читаемо, по крайней мере, на мой взгляд. Вы также могли бы написать это таким образом:

 if (myList.Count > 0)
{
    foreach (string myString in myList.Take(myList.Count - 1))
    {
         doSomething(myString);
    }

    doSomethingElse(myList.Last());
}
  

Вот еще одна альтернатива, которую я бы счел наиболее очевидной, но это, вероятно, самый быстрый способ сделать это:

 if (myList.Count > 0)
{
    for (int i = 0; i < myList.Count - 1; i  )
    {
        doSomething(myList[i]);
    }

    doSomethingElse(myList.Count - 1);
}