Когда использовать каждый тип петли? - PullRequest
4 голосов
/ 20 декабря 2010

Я изучаю основы программирования здесь (C #), но я думаю, что этот вопрос носит общий характер.

Какие простые практические ситуации подходят ближе к определенному типу цикла?

Циклы while и for кажутся довольно похожими, и есть несколько вопросов SO, касающихся различий между ними. Как насчет foreach? Из моего базового понимания кажется, что я должен быть способен делать все, что делает цикл foreach в цикле for.

Ответы [ 7 ]

9 голосов
/ 20 декабря 2010

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

while: если у вас есть условие, которое необходимо проверить в начале каждого цикла.Например, while(!file.EndOfFile) { }

for: если у вас есть индекс или счетчик, вы увеличиваете каждый цикл.for (int i = 0; i<array.Length; i++) { }.По сути, циклы, над которыми вы работаете, - это индексируемая коллекция, массив, список и т. Д.

foreach: когда вы циклически повторяете коллекцию объектов или другие перечисляемые объекты.В этом случае вы можете не знать (или не заботиться) о размере коллекции, или коллекция не основана на индексах (например, набор объектов).Обычно я считаю циклы foreach наиболее удобными для чтения, когда меня не интересует индекс чего-либо или какие-либо другие условия выхода.

В любом случае, это мои общие правила.

5 голосов
/ 20 декабря 2010

1.foreach и для

Цикл foreach работает с IEnumerator , когда цикл for работает с индексом (в object myObject = myListOfObjects[i], i - индекс).

Между ними существует большая разница:

  • индекс может напрямую обращаться к любому объекту в зависимости от его положения в списке.

  • перечислитель может получить доступ только к первому элементу списка, а затем перейти к следующему элементу (как описано в предыдущей ссылке из msdn).Он не может получить доступ к элементу напрямую, просто зная индекс элемента в списке.

Так что перечислитель может показаться менее мощным, но:

  • выне всегда знают положение элементов в группе, потому что все группы не упорядочены / не проиндексированы.
  • вы не всегда знаете количество элементов в списке (подумайте о связанном списке).
  • , даже когда он упорядочен, индексированный доступ к списку может быть основан на внутреннем перечислителе, что означает, что каждый раз, когда вы обращаетесь к элементу по его позиции, вы можете фактически перечислять все элементы списка вплоть доэлемент, который вы хотите.
  • индексы не всегда числовые.Подумайте о словаре .

Так что на самом деле большая сила цикла foreach и базовое использование IEnumerator заключается в том, что он применяется к любому типу, который реализует IEnumerable(реализация IEnumerable означает, что вы предоставляете метод, который возвращает перечислитель).Списки, массивы, словари и все другие типы групп реализуют IEnumerable.И вы можете быть уверены, что перечислитель, который у них есть, не уступает: вы не найдете самый быстрый способ просмотреть список.

Итак, цикл for может обычно следует рассматривать как специализированный foreach цикл:

public void GoThrough(List<object> myList)
{
    for (int i=0; i<myList.Count; i++)
    {
        MessageBox.Show(myList[i].ToString());
    }
}

совершенно эквивалентен:

public void GoThrough(List<object> myList)
{
    foreach (object item in myList)
    {
        MessageBox.Show(item.ToString());
    }
}

Я сказал обычно , потому что есть очевидный случайкогда необходим цикл for: когда по какой-то причине (например, при его отображении) вам нужен индекс (то есть позиция в списке) объекта.Однако в конечном итоге вы поймете, что это происходит только в определенных случаях , когда вы хорошо программируете .NET, и что foreach должен быть вашим кандидатом по умолчанию для циклов над группой элементов.

Теперь, чтобы продолжать сравнивать цикл foreach, он действительно очень интересен: цикл

public void GoThrough(IEnumerable myEnumerable)
{
    foreach (object obj in myEnumerable)
    {
        MessageBox.Show(obj.ToString());
    }
}

полностью эквивалентен:

public void GoThrough(IEnumerable myEnumerable)
{
    IEnumerator myEnumerator = myEnumerable.GetEnumerator();
    while (myEnumerator.MoveNext())
    {
        MessageBox.Show(myEnumerator.Current.ToString());
    }
}

Первая запись - этонамного проще, хотя.

2.while и do.. while

Цикл while (condition) {action} и цикл do {action} while (condition) просто отличаются друг от друга тем, что первый проверяет условие перед применением действия, когда второйприменяет действие, затем проверяет условие.Цикл do {..} while (..) используется весьма незначительно по сравнению с другими, поскольку он выполняет действие по крайней мере один раз, даже если условие изначально не выполняется (что может привести к проблемам, поскольку действие обычно зависит от условия).

Цикл while является более общим, чем циклы for и foreach, которые применяются конкретно к спискам объектов.Цикл while просто имеет условие для продолжения, которое может основываться на чем угодно.Например:

string name = string.empty;
while (name == string.empty)
{
    Console.WriteLine("Enter your name");
    name = Console.ReadLine();
}

просит пользователя ввести его имя, затем нажимать Enter, пока он на самом деле что-то не введет.Как видите, ничего общего со списками не имеет.

3.Заключение

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

Теперь закончим чем-то менее ограничительным: ваша первая цель в .NET должна состоять в том, чтобы сделать ваш код читабельным / поддерживаемым и , чтобы он работал быстро в том порядке приоритета.Все, что достигает, это хорошо для вас.Лично я думаю, что цикл foreach имеет то преимущество, что потенциально он наиболее читаемый и самый быстрый.

Edit: есть другой случай, когдацикл for полезен: когда вам нужно индексировать, чтобы пройти по списку особым образом, или если вам нужно изменить список в цикле.Например, в этом случае, потому что мы хотим удалить каждый нулевой элемент из myList:

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

Вам нужен цикл for, потому что myList нельзя изменить из цикла foreach, и нам нужноперейти назад, потому что, если вы удалите элемент в позиции i, положение всех элементов с индексом> i изменится.

Но использование этих специальных конструкций было сокращено после LINQ.Последний пример может быть написан так в LINQ, например:

myList.RemoveAll(obj => obj == null);

LINQ - это второй шаг, сначала изучите циклы.

2 голосов
/ 20 декабря 2010

когда вы знаете, сколько будет итераций, используйте for

, когда вы не знаете, используйте while, когда не знаете и нужно выполнить код хотя бы раз, используйте do

когда вы перебираете коллекцию и не нуждаетесь в использовании индекса foreach (также вы не можете использовать collection[i] для всего, что вы можете использовать foreach on)

1 голос
/ 20 декабря 2010

Цикл do while забыт, я думаю:)

Взято из здесь .

Оператор C # while выполняет оператор или блок операторов, пока указанное выражение не станет ложным. В некоторых ситуациях вы можете выполнить цикл хотя бы один раз, а затем проверить условие. В этом случае вы можете использовать do..while loop.

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

using System;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int count = 5;
            do{
                MessageBox.Show(" Loop Executed ");
                count++;
            }while (count <=4);
        }


        private void button2_Click(object sender, EventArgs e)
        {
            int count = 5;
            while (count <=4){
                MessageBox.Show(" Loop Executed ");
                count++;
            }
        }
    }
}
1 голос
/ 20 декабря 2010

Как уже говорили другие, «это зависит».

Я считаю, что в настоящее время я использую простые циклы for очень редко.Если вы начнете использовать Linq, вы обнаружите, что вам тоже не нужны циклы, а когда вы делаете это, вам нужен цикл 'foreach'.

В конечном итоге я согласен с Колином Маккеем - кодом для удобства чтения!

0 голосов
/ 20 декабря 2010

Если вы пишете класс синтаксического анализатора, скажем, XMLParser, который будет читать узлы XML из заданного источника, вы можете использовать цикл while, поскольку вы не знаете, сколько там тегов.Также вы можете использовать while, когда вы выполняете итерацию, если переменная имеет значение true или нет.

Вы можете использовать цикл, если хотите иметь немного больше контроля над своими итерациями

0 голосов
/ 20 декабря 2010

Если у вас есть коллекция, и вы заблаговременно говорите, что собираетесь систематически проходить через все значения, используйте foreach , поскольку с «текущим» экземпляром обычно проще работать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...