Страницы: Пред. 1 2 3 4 5 След.
RSS
Циклы и метки. В каких случаях, что использовать будет эффективнее
 
Пример использования Do......Loop
Код
Sub test1()
    'проверка на ввод текста циклом Do.....Loop
    Dim txt
    Do
        txt = InputBox("Введите текст")
        If Not IsNumeric(txt) Then Exit Do
    Loop
End Sub
Sub test2()
    'проверка на ввод числового значения циклом Do.....Loop
    Dim txt
    Do
        txt = InputBox("Введите Число")
        If IsNumeric(txt) Then Exit Do
    Loop
End Sub
"Все гениальное просто, а все простое гениально!!!"
 
Цитата
Jack Famous написал: тут, конечно, Select Case лучше, но смысл тот же…
Хуже, если такая плотная любовь-привязаность к меткам :)
Ну, зачем здесь-то они?
Код
Select Case s
Case 1: txt = "один"
Case 2: txt = "два"
Case 3: txt = "три"
End Select


Цитата
Jack Famous написал: Я бы просто описание ошибки в MsgBox передавал
Я показал кусок из работающей программы. Ошибка - текущая (оператор ошибся), которая не приводит к сбою или нехорошим последствиям. Тольк для информирования. Тот же MsgBox, но самозакрывающийся.
 
Nordheim, это вполне может заменить метки в моём примере с "возвратом", если добавить булеву переменную. Получится что-то такое
Код
Sub test()
Dim txt$,IfEr as Boolean
    Do
        If IfEr then MsgBox "Некорректный ввод"
        txt = InputBox("Введите текст")
        If Not IsNumeric(txt) Then Exit Do
        IfEr=1
    Loop
End Sub
это я понял - спасибо, надо тестить…

Цитата
vikttur написал:
Ну, зачем здесь-то они?
верно - незачем)) в этом случае я просто пытался визуализировать чужой подход ДО вашего примера. И про Select Case сказал  :)
Изменено: Jack Famous - 04.07.2018 13:52:52
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
OFF

Про уведомления. Достаточно успешно можно пользовать через шелл msg %username% /w /Time:4 "Test" , ну или с другими ключами. Правда есть риск что не заметят так как это окно будет не окном Excel, но … есть и плюсы, например программа продолжает работать дальше. %username% -можно заменить на * но тогда, в случае работы на терминалке, все получат это сообщение :-)
По вопросам из тем форума, личку не читаю.
 
БМВ, спасибо. shell пока не мой уровень))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Собрал тестовый стенд, но что-то не получается полностью воспроизвести пример с метками. Поправьте, пожалуйста.
Тестовый стенд
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Немного подправил код с циклом Do...Loop, вроде работает.
"Все гениальное просто, а все простое гениально!!!"
 
Nordheim, ввести классы для сообщений? Это сильно  :D полезно знать - спасибо (классы у меня в очереди на изучение), но я в этой ситуации бы не применил
Отсутствует проверка на 0 и отрицательные. Не даёт ввести десятичные ("16,4", например)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Вот могу ошибаться и более того хороший тон прибраться за собой, но кажется On Error GoTo 0 перед выходом не имеет смысла. Если я не ошибаюсь, то действие в пределах одной процедуры/функции. Если была ошибка и может повлиять на результат в коде родителя если там контроль ошибки ведется не выносной, то err.clear
По вопросам из тем форума, личку не читаю.
 
Цитата
Jack Famous написал:
но я в этой ситуации бы не применил
писанины столько же что и "GoTo er". У меня разделитель дробной части не , а . Поменяйте в строке
Код
If IsNumeric(ввод) And Len(Split(ввод, ".")(0)) <= 2 Then Exit Do
точку на запятую.
Изменено: Nordheim - 04.07.2018 15:21:24
"Все гениальное просто, а все простое гениально!!!"
 
Цитата
БМВ написал:
On Error GoTo 0 перед выходом не имеет смысла
в какой-то теме говорилось, что не всегда так. Тем более, если процедура или функция используется в других процедурах и функцияхNordheim, даёт ввести отрицательные и более 2х знаков.
Сделал вместо Len(Split(ввод, ",")(0))Len(Split(ввод, ",")(1)) — так работает, но с отрицательными осталась проблема.
Изменено: Jack Famous - 04.07.2018 15:28:39
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
Вот, собственно, пример кода с метками. Тот самый, о котором я вчера писал в оффтопе. Что и почему вы бы заменили в нём?
На мой субъективный взгляд, организация циклов и ветвлений в Вашем коде не режет глаз и в целом понятна и читаема (пусть даже сам я никогда так не пишу).
В отличие от префикса WF_ у каждой (каждой!) переменной. Если бы вдруг мне волею судеб пришлось модифицировать/рецензировать этот код, я бы начал с удаления этого префикса совсем, либо (если он несёт в себе какую-то смысловую нагрузку) его выноса в имя процедуры, а метки и структуру постарался бы оставить без изменений.
Почему я бы так поступил:
1) CapsLock традиционно резервируется под константы. Использование в другом контексте сбивает с толку.
2) Нижнее подчёркивание в VBA резервируется под имена событий и переносы строк. Использование в другом контексте, особенно с верхним регистром, сбивает с толку.
3) Префикс, который относится одновременно ко всем (или почти всем) переменным процедуры, избыточен в рамках этой процедуры, потому что итак ясно, что все переменные в ней - локальные, а ничего другого такой префикс не сообщает. Если вдруг в процедуре используются 1-2 переменные из внешних областей видимости, то всегда проще выделить как-то именно их, а не все остальные вплоть до индексов цикла.

По теме: сам я пользуюсь и For, и While, и For Each циклами, отталкиваясь от формулировки задачи и цели. Например, если по условию задачи циклу надо работать пока не будет выполнено какое-то условие, то и цикл использую While, а не For с выходом. Если надо выполнить операцию некоторое количество раз, например, перебрать все индексы массива от начала до конца, то цикл For. Если есть коллекция и надо что-то сделать с каждым её элементом, то For Each. Грубо говоря, стараюсь писать код как можно лексически ближе к псевдокоду.
Понятно, что циклы взаимозаменяемы в большинстве случаев, но использование циклов со счётчиками для задачи поиска условия сбивает с толку и заставляет ломать голову над тем, почему автор кода вдруг такое учудил.

А вот что действительно бесит иногда - это неявные циклы с помощью GoTo и условий. Потому что ключевые слова в купе с форматированием циклов сразу дают понять, что это - цикл, и показывают, где у него начало, а где конец, а не заставляют мучительно скакать глазами со строки на строку в поисках начала и конца итерации.
 
Цитата
Jack Famous написал:
в какой-то теме говорилось, что не всегда так.
Это про события было, а тут другое.

https://msdn.microsoft.com/en-us/VBA/language-reference-vba/articles/on-error-statement
On Error GoTo 0 disables error handling in the current procedure. It doesn't specify line 0 as the start of the error-handling code, even if the procedure contains a line numbered 0. Without an On Error GoTo 0 statement, an error handler is automatically disabled when a procedure is exited. To prevent error-handling code from running when no error has occurred, place an Exit Sub, Exit Function, or Exit Property statement immediately before the error-handling routine, as in the following fragment:
По вопросам из тем форума, личку не читаю.
 
Nordheim, написал UDF для "распознавания" числа из текста - уменьшило мой код, но не получилось применить к вашему.
В своём я сначала проверяю введённые данные по UDF (выхожу, если проверка не пройдена). Потом проверяю на положительность (выхожу, если нет). Таким образом, у меня по логике операций всё последовательно и работает. В вашем варианте нет возможности проверить пошагово, поэтому, при вводе текста, проверка на положительность вызовет критическую ошибку. И On Error Resume Next не поможет… А вот вызывать сообщения из классов, если классы в надстройке — штука крутая. Один раз записал и потом только вызываешь. Осталось только разобраться, как вызывать класс при непредвиденной ошибке (аналог "On Error GoTo er")
КОДЫ
Цитата
Irregular Expression написал:
я бы начал с удаления этого префикса совсем
использую (только в UDF в надстройке) больше для перестраховки, чтобы гарантированно не задублировать переменные при вызове из других процедур и функций
Цитата
Irregular Expression написал:
неявные циклы с помощью GoTo и условий
я, слава богу, не встречал))) в целом, во всём согласен с вами  :)

БМВ, надо тестить))) ссыкотно мне  :D
Изменено: Jack Famous - 04.07.2018 16:10:29
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Irregular Expression написал:
А вот что действительно бесит иногда - это неявные циклы с помощью GoTo и условий. Потому что ключевые слова в купе с форматированием циклов сразу дают понять, что это - цикл, и показывают, где у него начало, а где конец, а не заставляют мучительно скакать глазами со строки на строку в поисках начала и конца итерации.
Вот полностью согласен. это как раз то с чем я столкнулся начав писать более менее сложный код, и из-за чего перестал использовать GoTo
"Все гениальное просто, а все простое гениально!!!"
 
Цитата
Jack Famous написал:
где Do-Loop наиболее эффективен по сравнению с For-Next и If-Then
Например, при удалении строк по критерию.
Код
i=1
Do While i<Cells(Rows.Count,1).End(xlUp).row
    If Cells(i,2).Value=1 Then Rows(i).Delete Else i=i+1
Loop

C For-Next будет много геморроя.
Изменено: StoTisteg - 05.07.2018 10:25:51
 
Цитата
Neufazendnik написал:
В нем нет скрытного механизма приращения счетчика и ограничений на использование счетчика после покидания тела цикла
У For-Next тоже нет. Зато возможность с помощью счётчика проверить, как был покинут цикл, очень полезна, например, при поиске полным перебором.
 
Цитата
StoTisteg написал:
C For-Next будет много геморроя
не думаю. Удаление строк по критерию:
Код
lr=Cells(Rows.Count,1).End(xlUp).Row

' обратный цикл (медленно)
     For i=lr To 1 Step -1
          if Cells(i,2)=1 Then Rows(i).Delete
     Next i

' сбор и удаление скопом (быстро)
Set rng=Range("B1:B" & lr)
     For each cl in rng
          If cl.Value=1 Then
               If gr is Nothing Then Set gr=cl: Else: Set gr=Application.Union(gr,cl)
          End If
     Next cl
If Not gr Is Nothing Then gr.EntireRow.Delete
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
StoTisteg написал:
C For-Next будет много геморроя.
Абсолютно никакого геморроя

Код
Sub test()
    Dim i&
    For i = Range("a" & Rows.Count).End(xlUp).Row To 1 Step -1
        If Cells(i, 1).Value = 1 Then Rows(i).Delete
    Next i
End Sub
"Все гениальное просто, а все простое гениально!!!"
 
Jack Famous, range().entirerow.delete - без всякого цикла.
Сорри, поспешил. Не увидел, что у Вас там условие... Отбой.
Изменено: Neufazendnik - 05.07.2018 11:11:49
 
Neufazendnik, не понял
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous,Да ступил я. Все нормально у Вас в цикле. Я почему-то подумал, что Вы все строки без условия блоком трёте.
 
А как же условие?
 
vikttur, Ну, можно извратиться и с условием все равно без цикла соорудить. Добавить в таблицу скажем в 10й столбец формулу, вызывающую ошибку в этом столбце при появлении единицы в первой колонке и далее удаление всех лишних строк делать одной строкой кода
range(cells(1,10),cells(lr,10)).specialcells(xlCellTypeFormulas,xlErrors).entirerow.delete
Изменено: Neufazendnik - 05.07.2018 11:48:21
 
Цитата
Neufazendnik написал:
извратиться
Ключевое слово данного способа  :D
"Все гениальное просто, а все простое гениально!!!"
 
Использую Do.....Loop в таком коде:

Код
Sub ПереборФайловВПапке()
    Dim iPath$, FileName$
    iPath = ThisWorkbook.Path & Application.PathSeparator
    FileName = Dir(iPath & "*.xls*")
    If FileName = "" Then Exit Sub
    Do Until FileName = ""
        Debug.Print FileName
        FileName = Dir
    Loop
End Sub

Можно в данном случае использовать For...Next, но перед этим необходимо заполнить массив,
так же можно перебрать с помощью FileSystemObject но этот вариант сложней. Поэтому нашел самый оптимальный циклом Do...Loop
"Все гениальное просто, а все простое гениально!!!"
 
Цитата
Jack Famous написал:
чтобы гарантированно не задублировать переменные при вызове из других процедур и функций
Все переменные, объявленные внутри процедуры, видимы только в пределах этой процедуры/функции. Если я вызову процедуру с циклом For i внутри цикла For i другой процедуры, у меня переменные i гарантировано не пересекутся никогда :).
"Задублировать" переменную при вызове процедуры/функции из другой процедуры/функции нельзя никак.
Единственный способ добиться такой ошибки в своём коде - пересечение имён глобальных переменных с локальными. Поэтому и общепринято использовать разный синтаксис для именования переменных разных областей видимости (например, писать глобальные CapsLock'ом).
Изменено: Irregular Expression - 05.07.2018 12:44:03
 
Цитата
Irregular Expression написал:
"Задублировать" переменную при вызове процедуры/функции из другой процедуры/функции нельзя никак.
Это в теории. А на практике в коде можно планировать обратиться к переменной уровня модуля и совсем забыть, что она же у тебя определена в текущей процедуре. Это и будет то самое "задублировать", о котором шла речь.
 
Neufazendnik, переменные уровня модуля - разновидность глобальных переменных, т.е. именно тот случай, о котором я сказал выше: надо использовать разный синтаксис имён переменных для разных областей видимости, и такая ошибка никогда Вас не посетит.
А "забыть", что переменная уже объявлена, можно и в рамках одной процедуры :).
 
Nordheim, да - наверное в этом случае проще перебирать до пустоты, чем заранее формировать массив :idea:
спасибо за пример!

Irregular Expression, спасибо вам!))) протестирую и буду планомерно избавляться  ;)
глобальные переменные у меня точно уникальны (тоже заранее перестраховался)
Изменено: Jack Famous - 05.07.2018 13:04:56
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: Пред. 1 2 3 4 5 След.
Наверх