Страницы: 1 2 След.
RSS
Do...Loop круче For...Next
 
Добрый день.
Подскажите, что может Do...Loop такого, что нельзя сделать при помощи For...Next или If,  или иного оператора?
Никогда на ум не приходит использовать Do...Loop.
Может я неправ?
"..Сладку ягоду рвали вместе, горьку ягоду я одна."
 
Во-первых, сравнивать Do...Loop и If - неправильно. Одна является конструкцией цикла, а вторая условия.
В отличии от For Next - Do ... Loop может быть использован для вычисления неизвестных величин, если цикл должен продолжаться не по жестко заданным элементам, а до тех пор, пока условие не будет выполнено.
Например, если необходимо изменять значения указанных ячеек до тех пор, пока их сумма не станет равна определенному указанному значению(или приближенной к нему). For ... Next здесь явно не справится.

Так же Do ... Loop применяется вместе с Find для определения всех найденных значений(пример есть в офф.справке по методу Find-FindNext). Применить иной цикл не представляется возможным именно с Find, т.к. неизвестно заранее сколько значений будет найдено. При этом часто такой подход применяется для одновременной замены или удаления найденного, что дополнительно усложняет выполнение задачи иными средствами.

Правда, в Do .. Loop надо очень аккуратно относится к условиям, дабы не завесить ПК. Поэтому часто в этот цикл вставляется DoEvents, чтобы можно было прервать цикл, если он "ушел в бесконечность"(условие недостижимо вследствие ошибки программиста).
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
в Do Loop не всегда будет первый проход, в For Next - всегда.
Неизлечимых болезней нет, есть неизлечимые люди.
 
Цитата
TheBestOfTheBest написал: For Next - всегда.
:-)
Код
For 1 to 0
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Практически никогда не использую Do...Loop.
Но есть случай когда очень годится - например нужен цикл в цикле, и из которых всех нужно выйти, если во внутреннем выполнилось условие.
Тогда внешний ставим Do...Loop, внутренний For...Next, а в нём когда нужно выполняем Exit Do

Код
Do
  for i=1 to 3
    for j=5 to 8
      for each x in MyArray
        if SomeCondition then exit do
      next
    next
  next
Loop until true
Ну или можно сделать наоборот.
 
Или вот что где-то говорил Казанский:

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

1. Цикл For Each можно использовать не только для перебора элементов коллекции (например, коллекции ячеек в диапазоне), но и для перебора элементов массива. Причем массив может формироваться "тут же" функцией Array или Split. Этот фрагмент перевернет названия перечисленных листов:
Код
Dim s
For Each s In Array("Лист1", "Лист3")
Sheets(s).Name = StrReverse(Sheets(s).Name)
Next
или
Код
Dim s
For Each s In Split("Лист1,Лист3", ",")
Sheets(s).Name = StrReverse(Sheets(s).Name)
Next

2. Цикл Do...Loop вполне может использоваться без While или Until, если предусмотрен выход из цикла с помощью Exit Do. Этот фрагмент будет выдавать сообщение, пока пользователь не нажмет "Отмена" или "крестик":
Код
Do
If MsgBox(IIf(Rnd() < 0.5, "Орел", "Решка"), vbOKCancel) = vbCancel Then Exit Do
Loop

3. После "нормального" выхода из цикла For Each, переменная цикла содержит Nothing. Это можно использовать для определения того, как произошел выход из цикла - после перебора последнего элемента или по Exit For. Этот фрагмент определяет, содержится ли в книге лист с заданным именем:
Код
Dim sh As Worksheet
For Each sh In Worksheets
If sh.Name = "Лист2" Then Exit For
Next
If sh Is Nothing Then MsgBox "Лист не найден": Exit Sub
 
Do loop использую, когда точно не знаю рамок применения цикла, а использовать дополнительную переменную не представляется возможным (примерно как в ответе The Priest про find). Если все же возникает необходимость использовать Do loop, надо быть осторожным в том смысле, что нужно обновлять условие, которое идет для сравнения в while, until. Если обновление сравниваемой переменной задано некорректно, мы можем попасть в бесконечный цикл (infinite loop). Именно по этой причине в любых циклах (в том числе и в for loop, если рамки слишком большие) желательно использовать DoEvents, как уже сказано выше. For loop обычно имеет конечные рамки, которые задаются жесткими цифрами (hardcoded values) либо переменными, значения которых мы как-то изначально получаем. Типичный пример - прогон массивов.

Вообще надо, где удобно, уходить от циклов, используя при этом блок on error resume next - on error goto 0. Например алгоритм перебора файлов, который имеет линейную комплексность, может стать по комплексности константой, но это уже совсем другая история.
С уважением,
Федор/Все_просто
 
Цитата
Все_просто написал:
Вообще надо, где удобно, уходить от циклов, используя при этом блок on error resume next
здесь не соглашусь. Обходы ошибок это не совсем правильный вариант. Если есть вариант без этого - лучше использовать его. Почему нет, если все используют и горя не знают? Все просто: по умолчанию в настройках VBE установлено: Tools-Options-вкладка General-Breack on unhandled Errors. Но если кто-то сменит и установит: Breack on All Errors - то On Error Resume Next будет бесполезен.
Поэкспериментируйте с этими настройками и с кодом:
Код
Sub test()Dim wsSh As Worksheet
On Error Resume Next
Set wsSh = Sheets("Лист5")
If wsSh Is Nothing Then
    MsgBox "Нет такого листа"
End If
End Sub
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
The_Prist написал: For 1 to 0
попробуйте, гы, первый проход все равно будет, т.к. условие цикла проверяется по строке Next
Перепутал с Do...until
Изменено: TheBestOfTheBest - 23.04.2015 18:52:10
Неизлечимых болезней нет, есть неизлечимые люди.
 
Цитата
TheBestOfTheBest написал: попробуйте, гы, первый проход все равно будет
8-0
Код
Sub test()
Dim li As Long
For li = 1 To 0
MsgBox "А был ли проход?"
Next
End Sub
Вы ничего не перепутали, когда писали, что у Next всегда будет проход, а у Loop нет? Вы либо определитесь - будет ли проверка условия, либо изучите мат.часть. Любой цикл сначала оценивает условия и входные данные. И после этого уже либо будет проход цикла(хотя бы одна итерация) - либо нет.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
The_Prist написал: Любой цикл сначала оценивает условия и входные данные
Тогда и вы учите матчасть :)
Код
Do
MsgBox "А был ли проход?"
Loop Until True
Неизлечимых болезней нет, есть неизлечимые люди.
 
Цитата
TheBestOfTheBest написал:
в Do Loop не всегда будет первый проход, в For Next - всегда
а это кто писал?
Цитата
TheBestOfTheBest написал:
Тогда и вы учите матчасть
Уверены, что это я должен сделать?
Я даже в Вашем утверждении выделил жирным указание на некорректность.

И в Вашем последнем примере кода лишь подтверждение моих слов. В приведенном примере Do сначала оценивает входные данные и условия. Т.к. в Вашем примере условия идут после прохода и отсутствуют в начале(специфика конструкции) - идет первый проход цикла и после сопоставление условия. For ... Next лишен такой возможности и обязан всегда определять для начала входные условия(границы итераций) и только после этого принять решение - делать проход или нет.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Прочтите пост #9
Неизлечимых болезней нет, есть неизлечимые люди.
 
Хватит ругаться, ребята.
---------------------------------------------------
Вообщем, с примерами стало чуть понятнее. Видно с такими ситуациями я ещё пока не сталкивался.
Спасибо.
Всего доброго.
"..Сладку ягоду рвали вместе, горьку ягоду я одна."
 
Скрытый текст
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Скрытый текст
Неизлечимых болезней нет, есть неизлечимые люди.
 
Ну давайте разбираться. Вы изначально писали про Next. На это и была львиная доля ответов. Которые Вы читали вскользь, не пытаясь понять, что помимо непосредственно условий истинности(i<> и т.п.) есть входные данные. Чтобы Вы ни думали, но перед выполнением цикла сначала оцениваются входные данные:
-для For ... Next - границы цикла(начальная итерация и конечная)
-для Do - наличие условий проверки и тип проверки: While,Until и их месторасположение относительно исполняющей конструкции.

И именно исходя из этих данных VBE определяет - надо делать первый проход или нет.  В случае с Do вообще неверно утверждать ни наличие прохода ни его отсутствие не приводя конкретный тип конструкции Do.
Ниже несколько разных циклов с Do. test3 и test 4 будут делать первый проход в любом случае, т.к. условие истинности расположено после прохода. test1 и test2 - могут отработать без единого прохода, в зависимости от истинности указанного условия.
Код
Sub test()
    Dim i
    i = 0
    Do While i <> 1
        MsgBox "А был ли проход?"
        i = 1
    Loop
End Sub
Sub test2()
    Dim i
    i = 0
    Do Until i <> 1
        MsgBox "А был ли проход?"
        i = 1
    Loop
End Sub
Sub test3()
    Dim i
    i = 0
    Do
        MsgBox "А был ли проход?"
        i = 1
    Loop While i <> 1
End Sub
Sub test4()
    Dim i
    i = 1
    Do
        MsgBox "А был ли проход?"
    Loop Until i = 1
End Sub

Я уже не стал приводить примеры вообще без проверки условий, опирающиеся на флаги. Там и так понятно, что в любом случае будет проход.
Выше я уже приводил пример отказа в проходе в цикле For, поэтому не вижу смысла выкладывать его здесь еще раз.

И чтобы не было недопонимания: проходом лично я считаю в данном случае инструкции, расположенные между Do и Loop и между For и Next.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Тогда к вам такой вопрос, конструкция test5() имеет цикл?
Код
Sub test5()
Dim i
    i = 0
    Do
        MsgBox "А был ли проход?"
    Loop Until i = 1
End sub 
Имеет.
Хотя бы один проход будет в любом случае (кроме ошибки выполнения кончно).
Поэтому, я утверждаю что Do...Loop может организовать цикл с первым обязательным проходом не зависимо от условия цикла. For ... Next такого не может, придется изменять его счетчик.
Я не прав?
Изменено: TheBestOfTheBest - 23.04.2015 14:39:24
Неизлечимых болезней нет, есть неизлечимые люди.
 
Цитата
TheBestOfTheBest написал: я утверждаю что Do...Loop может организовать
Во-первых все началось с того, что утверждали-то Вы обратное. Нет?
Во-вторых:
Цитата
The_Prist написал: В случае с Do вообще неверно утверждать ни наличие прохода ни его отсутствие не приводя конкретный тип конструкции Do
Вы бы хотя бы мои сообщения читали. Я же сам выше привел циклы и расписал какие из них будут иметь минимум один проход, а какие нет.

Да, в приведенном Вами последнем примере будет в любом случае один проход. Но как это опровергает мои утверждения? Я вот этого не пойму. Еще раз написать? СНАЧАЛА ПРОВЕРЯЮТСЯ ВСЕ ВХОДНЫЕ ДАННЫЕ для определения цикла в принципе. Вводные данные, если угодно. Do имеет несколько реализаций и VBE должен сначала понять какая перед ним в данный момент. Если сразу после Do нет условия - значит сначала будет выполнен проход в любому случае. Если условие есть - то будет проверено это условие и после этого принято решение - делать проход или нет.
Поэтому я и написал: нельзя утверждать, что у Do .. Loop всегда есть один проход, не приводя конкретную конструкцию. Все зависит именно от конструкции в случае с Do и обобщать тут нельзя. Это все равно, что утверждать, что у машины всегда 4 колеса.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
Владимир написал: Хватит ругаться, ребята
В споре рождается истина :-)
Именно в таких вот перепалках и можно открыть для себя порой что-то новое. Ну или закрепить старое...
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Вот же как хорошо получается! Двое спорят, а истину, которая рождается, все на ус мотают :)
Копирну-ка я эту тему себе с справку.
 
Цитата
The_Prist написал: Но как это опровергает мои утверждения?
Мне показалось, что формулировка "Любой цикл сначала оценивает условия и входные данные" некорректна, т.к. в test5() условие оценивается в конце цикла. Вы сами об этом пишите. Про входные данные не знаю, таких в коде я не вижу, есть оператор/конструкция Do...Loop и условие, приставленное к Do или к Loop. Как написано, так VBA и исполняет. Может вы дадите ссылку где написано про "Любой цикл сначала оценивает условия и входные данные", я поизучаю матчасть.

Могу вот что еще добавить. Организация For Next всегда требует счетчика, с соответствующими заморочками (объявление переменных, присвоение значений TO и STEP), Do же этого не требует, здесь надо следить за условием, которое не требует счетчика.
Изменено: TheBestOfTheBest - 23.04.2015 15:19:02
Неизлечимых болезней нет, есть неизлечимые люди.
 
Я уж и не знаю как написать-то, чтобы Вы поняли...
Цитата
The_Prist написал: Do имеет несколько реализаций и VBE должен сначала понять какая перед ним в данный момент
ни на какие мысли не наводит? :-) Вы чуть передохните, обдумайте и заново перечитайте тему. Под входными данными в данном случае я понимаю конкретизацию цикла: это For ... Next, Do ... Loop, Do While ... Loop и т.д.
Т.е. VBE должен в любом случае понять, что за цикл перед ним. Нет для него понятия: любой Do сначала делает проход. Как видно - их несколько реализаций, этих Do. И нельзя утверждать, что "Do всегда делает один проход". Я выше выкладывал 4 цикла - два из них сделают проход в любом случае, два - только в зависимости от условия. И все они относятся к семейству Do.
Цитата
Я отвечал в противовес Вашему утверждению:
TheBestOfTheBest написал: первый проход все равно будет
Ведь Вы ответили человеку, который Do впервые видит. И ответили мало того, что изначально неверно, так и потом не конкретизировали, а отнесли все реализации циклов Do в одну свалку(а-ля они все имеют по-любому один проход). Это же неверно. Что я и пытаюсь до Вас донести.

А ссылку на матчасть не дам, т.к. это на MSDN все расписано, но не в таком явном виде и не для VBA конкретно...
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
The_Prist написал: а отнесли все реализации циклов Do в одну свалку(а-ля они все имеют по-любому один проход). Это же неверно
Разве утверждение ниже не верно?

Цитата
TheBestOfTheBest написал: Поэтому, я утверждаю что Do...Loop может организовать цикл с первым обязательным проходом не зависимо от условия цикла
Написано "может организовать", а не "должен организовать" - я это поправил и извинился за прежний ляп. Конкретику дал в коде.

Я бы очень хотел увидеть официальный источник, где есть такие формулировки "Под входными данными в данном случае ... конкретизацию цикла: это For ... Next, Do ... Loop, Do While ... Loop и т.д." или "Любой цикл сначала оценивает условия и входные данные...". Жду ссылку.
Неизлечимых болезней нет, есть неизлечимые люди.
 
Цитата
TheBestOfTheBest написал: Жду ссылку.
Ждите. Я Вам ничего не должен и не собираюсь при таком подходе вообще Вам что-то давать или разъяснять. Я уже писал, что именно я имел под входными данными: наличие условия или его отсутствие. Т.е. признак, указывающий на тип цикла. Раз читать и вдумываться не хотите - есть MSDN - лопатьте сами, упрямства Вам не занимать. Расценивать это можете тоже как хотите. Мне уже отсюда видно, что бесполезно до Вас пытаться что-то донести. Поэтому лопатьте офф.источники и ищите там все, что душе угодно.

Также можете дальше смело делать ляпы на форумах и не обращать внимания, когда Вас пытаются корректно поправить. Кстати, раз уж Вы первый на конкретные слова стали обращать внимание(типа "я же написал может" - несмотря на то, что я и не отрицал этого):
Цитата
TheBestOfTheBest написал: Организация For Next всегда требует счетчика, с соответствующими заморочками (объявление переменных, присвоение значений TO и STEP), Do же этого не требует
Вы уверены?
Код
Sub test5()
For Each x In Range("A1:A10").Value
    MsgBox x
Next
End Sub

нет счетчика, нет To. Так же нет Step - он по умолчанию указан как 1. При этом директиву Option Explicit я убрал из модуля. И все работает без объявления. По-Вашему, Next всегда требует объявления переменных, а Do нет? А что отвечает за обязательное объявление переменных не напомните? Может имелось ввиду наличие некоей переменной цикла все же?


Может все же чуть отдохнете и вдумаетесь в тему в целом? Может тогда поймете о чем я вообще тут писал. Циклы бывают разные и нельзя мерить единым мерилом и единые утверждения для них лепить. Равно как и сравнить какой лучше - всякий хорошо по своему в зависимости от задачи.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Не пойму предмет спора...
вот справка VBA

Я думаю, компилятор всяко должен понять, какая конструкция использована - с условиями в начале и/или в конце, затем проверить их - либо в начале, либо в конце. Он же не построчно компилирует (как буквальный перевод), а по смыслу (литературно), нет?
F1 творит чудеса
 
Цитата
The_Prist написал: имелось ввиду наличие некоей переменной цикла
Да счетчик цикла. Без переменной x конструкция работать не будет. Или x не переменная? ;)

Хорошо, хорошо, я сдаюсь. Ваше эго круче.

PS Кстати "директиву Option Explicit я убрал из модуля. И все работает без объявления." -  у меня не работает, говорит переменная не определена :cry:
Изменено: TheBestOfTheBest - 23.04.2015 17:11:42
Неизлечимых болезней нет, есть неизлечимые люди.
 
Прикольная дискуссия здесь.

По существу вопроса Владимира:
Do Loop и For Next - это разные типы циклов, и их необходимо использовать в разных ситуациях.

Для себя использую
For i=a to b:Next i - в качестве счетчика или перебора элементов массива по индексу
For Each x in collection:next x - для перебора элементов коллекция или массивов.
Do Loop/While Wend - для циклов по условию

обычно конструкцию Do While условие:Loop заменяю на While условие:Wend, если это возможно (привычка экономии двух символов обусловленна решением олимпиадных задач по программированию)
но Do Loop, как правило, удобнее использовать(вместо While Wend): можно использовать различные условия выхода While или Until, условия ставить в начале или в конце цикла, а также есть возможность использования Exit Do при необходимости выйти по условию в теле цикла, или при вложенности нескольких циклов, как писал Игорь в 5 посте.
Изменено: MCH - 23.04.2015 17:08:36
 
Цитата
Максим Зеленский написал:
Я думаю, компилятор всяко должен понять, какая конструкция использована - с условиями в начале и/или в конце, затем проверить их - либо в начале, либо в конце
Началось с поста 3, где прозвучало утверждение, что For ... Next в отличие от Do .. Loop всегда будет делать минимум один проход. Я подумал, что скорее всего опечатка - но после первого примера был как бы...Отправлен проверять свое опровержение. После того, как TheBestOfTheBest понял ошибку я уже пытался рассказать, что каждый цикл - разный. И нельзя однозначно сказать ни про Do ... Loop, ни про For ... Next, если не указать конкретную конструкцию.
VBE когда встречает DO начинает искать дальше условие сразу после Do(While,Untill). Если не находит - идет на следующую строку и выполняет конструкцию внутри цикла после чего ищет Loop(как замыкающее звено цикла) и после этого уже ищет опять условие, чтобы понять - завершать цикл или вернуться в петлю. Т.е. это процесс изнутри так происходит. В принципе, как и If ... Then и любая другая встроенная "конструкция".

Цитата
TheBestOfTheBest написал:
Ваше эго круче
А я тут ничем не мерялся и в мыслях этого не держал. Я уже пояснил причину своих сообщений Вам - Вы выкладываете утверждения, которые не всегда верны(по крайней мере в преподнесенном Вами изложении). Почитайте со стороны - не скажешь ведь, не зная, что имелось ввиду не отсутствие шага и наличие счетчика, а наличие переменной цикла(без которой For ... Next немыслим). И тем более не скажешь, что имелось ввиду наоборот Do ... Loop, а не For ... Next.
А ведь Вы на форуме грамотные решения выкладываете. Как следствие - люди будут читать Ваш подобный ответ и принимать за чистую монету.

Если Option Explicit закомментирована или вообще отсутствует(что, собственно говоря для проекта равнозначно) - VBE не станет ругаться на необъявленную переменную, а просто применит к переменной с необъявленным типом директиву DefVar(т.е. тип Variant). И это справедливо для всех версий офиса и для VB(.NET не берем). Попробуйте скомпилировать проект после изменений. Вероятно некоторый глюк имеется в файле или в офисе в целом.
Цитата
TheBestOfTheBest написал:
Или x не переменная?
Переменная. Но, мне кажется, что это не Ваши слова, а мои. Ваши слова звучали иначе:
Цитата
TheBestOfTheBest написал:
Организация For Next всегда требует счетчика, с соответствующими заморочками (объявление переменных, присвоение значений TO и STEP)
Разница налицо. И опять же - утверждение Ваше безаппеляционное и без каких-либо оговорок. И как следствие неверное в этом преподнесении. Если брать For i = n To k - то-таки да. Но не в целом для For ... Next. О чем я опять же и написал.

В общем: я на этом откланиваюсь, для меня тема исчерпана(в части циклов, по крайней мере). Торжество эго оставлю Вам.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Какjе-то недопонимание The_Prist.
Да пост 3 моя ошибка, я поправился, вы же меня и поправили.

Вы в коде test5() переменную х использовали? Использовали. Я об этом же написал: "Организация For Next всегда требует счетчика,..."  У вас в цикле он неявный и как следствие необъявленный, да еще и не число, а объект. Ну и что? Функция счетчика не пропала, система сама её реализовала, как впрочем и TO и STEP.
Вы не можете предъявить конструкцию где For Next не содержит такой переменной по которой идет "счет". Ведь так? Значит счетчик в цикле есть.

Да, если не ставить Option Explicit ругаться не будет (у меня заругался на другое), но счетчик при этом не исчез, переменная не исчезла.

Повторюсь:
"Организация For Next всегда требует счетчика, с соответствующими заморочками (объявление переменных, присвоение значений TO и STEP)"
*счетчик - см. объяснение выше
**заморочки - возможные дополнительные строки кода (но не обязательные)

Не вижу безапелляционности, тем более для начинающего кодера VBA.
Неизлечимых болезней нет, есть неизлечимые люди.
Страницы: 1 2 След.
Наверх