Страницы: 1
RSS
Работа с циклами
 
Мне нужно удалить строки, определенные ячейки которых содержат значение "нет". Я сделал макрос:  
Sub test()  
   Dim oCell As Range  
   For Each oCell In Range([B1], Range("B" & Rows.Count).End(xlUp)).Cells
       If oCell.Value = "нет" Then Rows(oCell.Row).Delete  
   Next  
   For Each oCell In Range([I1], Range("I" & Rows.Count).End(xlUp)).Cells
       If oCell.Value = "нет" Then Rows(oCell.Row).Delete  
   Next  
End Sub  
То есть проверять мне нужно только два столбца, B и I.    
Но почему-то срабатывает только первый цикл по столбцу В. Второй цикл не работает. Почему?
 
Я сам разобрался, прошу прощения!
 
Вот это должно работать (не проверял)  
 
Sub test()  
   Dim oCell As Range, rng As Range  
   Dim i As Long  
     
   Application.ScreenUpdating = False  
     
   With ActiveSheet  
       Set rng = Range(Cells(1, "B"), Cells(Rows.Count, "B").End(xlUp))  
   End With  
     
   For i = rng.Count To 1 Step -1  
       Select Case "íåò"  
       Case rng(i, 1), rng(i, 9): rng(i).EntireRow.Delete  
       End Select  
   Next i  
     
   Application.ScreenUpdating = True  
End Sub
KL
 
Упссс... Опять кодировка :-)  
 
Вот это должно работать (не проверял)  
 
Sub test()  
Dim oCell As Range, rng As Range  
Dim i As Long  
 
Application.ScreenUpdating = False  
 
With ActiveSheet  
Set rng = Range(Cells(1, "B"), Cells(Rows.Count, "B").End(xlUp))  
End With  
 
For i = rng.Count To 1 Step -1  
Select Case "нет"  
Case rng(i, 1), rng(i, 9): rng(i).EntireRow.Delete  
End Select  
Next i  
 
Application.ScreenUpdating = True  
End Sub
KL
 
* в rng(i, 9) должна быть восьмерка, а не девятка, т.е. rng(i, 8)
KL
 
Вопрос спецам по VBA excel.  
А есть ли возможность функцией Excel получить диапазон ячеек, содержащих слово "нет", чтобы потом удалить все строки этого лиапазона?  
 
Что-то типа такого:  
[НекаяФункцияЛиста(b1:b1000, "нет")].entirerow.delete
 
Или только цикл?
 
1) можно циклом получить Union, а потом удалить все разом.  
Проблемы:  
a. присоединение к Union - крайне медленное действие в VBA  
б. ограничение на количество несмежных областей при удалении  
 
2) можно циклом получить адрес типа ("A1,B1,D2,G55"), а потом удалить все разом.  
Проблемы:  
a. ограничение на длинну строки адреса  
б. ограничение на количество несмежных областей при удалении
KL
 
То есть получается, что при обработке больших массивов информации лучше пользоваться Вашим первым, KL, макросом?
 
> 1) можно циклом получить Union, а потом удалить все разом.  
Это я знаю, так всегда и делаю.  
А вот про ограничение на количество несмежных областей при удалении хотелось бы узнать поподробнее...    
 
> можно циклом получить адрес типа ("A1,B1,D2,G55"), а потом удалить все разом.  
Так тоже как-то делал (при очень большом объёме данных)  
Как выяснилось, это самый быстрый способ.  
А ограничение на длину строки адреса удалось обойти, формируя не одну строку адреса, а массив таких строк (длина каждой строки <=255 символов)  
 
PS: Просто я неоднократно видел на форумах такие конструкции:  
.Offset(, 1).Value = [A1:A10+5]
.Offset(, 1).Resize(1).Value = Join([transpose(a1:a10)], ",")
 
Вот и подумал, что, может быть, получится средствами функций листа получить диапазон ячеек, содержащих определённое слово.  
Такие задачи встречаются довольно часто, и уже надоело писать несколько строк кода с использованием UNION.  
Хочется более элегантного решения :)
 
>> можно циклом получить адрес типа ("A1,B1,D2,G55"), а потом удалить все разом.  
>Так тоже как-то делал (при очень большом объёме данных)  
>Как выяснилось, это самый быстрый способ.  
Если это самый быстрый способ при обработке большого массива информации, можете подсказать код операции? Я пока слабо понимаю, как он должен выглядеть.
 
Сколько строк в Вашем файле?  
Если несколько тысяч, то вполне подойдёт способ с Union  
Если же десятки тысяч, то тогда можно подумать о более быстрых способах...
 
{quote}{login=EducatedFool}{date=11.08.2009 05:57}{thema=}{post}Вопрос спецам по VBA excel.  
А есть ли возможность функцией Excel получить диапазон ячеек, содержащих слово "нет", чтобы потом удалить все строки этого лиапазона?  
 
Что-то типа такого:  
[НекаяФункцияЛиста(b1:b1000, "нет")].entirerow.delete
 
Или только цикл?{/post}{/quote}  
 
Можно так:  
 
Function CondRange(Cond, Rng As Range) As Range  
 Dim x As Range, RngDif As Range  
 Set x = Rng.Find(What:=Cond, LookIn:=xlValues, LookAt:=xlWhole)  
 If x Is Nothing Then Exit Function  
 With Intersect(Rng.Parent.UsedRange, Rng)  
   On Error Resume Next  
   Set RngDif = .ColumnDifferences(x).EntireRow  
   If RngDif Is Nothing Then  
     Set CondRange = .Cells  
   Else  
     RngDif.Hidden = True  
     Set CondRange = .SpecialCells(xlCellTypeVisible)  
     RngDif.Hidden = False  
   End If  
 End With  
End Function  
 
Sub Test()  
 Dim Rng As Range  
 Set Rng = CondRange("нет", Columns(1))  
 If Not Rng Is Nothing Then Rng.Select: Debug.Print Rng.Address  
End Sub
 
> Если это самый быстрый способ при обработке большого массива информации, можете подсказать код операции?  
 
Посмотрите здесь:  
http://www.programmersforum.ru/showthread.php?t=31155&page=2  
 
 
> Можно так: Function CondRange(Cond, Rng As Range) As Range  
Большое спасибо, буду использовать.  
Не знал про ColumnDifferences...
 
{quote}{login=ZVI}{date=11.08.2009 07:07}{thema=Функция: CondRange()}{post}  
Можно так:...{/post}{/quote}  
Уверен, что ZVI про это знает :-) Для тех же, кто не в курсе:  
данный код имеет ограничение в 8.192 несмежные области, т.е. с абсолютной уверенностью его можно применять в столбце состоящем из 16.384 строк.
KL
 
{quote}{login=}{date=11.08.2009 06:22}{thema=}{post}PS: Просто я неоднократно видел на форумах такие конструкции:  
.Offset(, 1).Value = [A1:A10+5]
.Offset(, 1).Resize(1).Value = Join([transpose(a1:a10)], ",")
 
Вот и подумал, что, может быть, получится средствами функций листа получить диапазон ячеек, содержащих определённое слово.{/post}{/quote}  
Да, я иногда так делаю, но у этого решения проблем две:  
- не слишком "user-friendly"  
- ограничение в 255 символов  
 
Sub Test2()  
   Dim x As String, y As Range  
   x = Replace(Application.Trim(Join([TRANSPOSE(IF(A1:A150="нет","A"&ROW(A1:A150)," "))])), " ", ",")
   Set y = Range(x)  
End Sub
KL
 
Спасибо за идею.  
Ограничение в 255 символов - это, конечно, плохо, ибо сводит все усилия на нет.  
А насчёт "user-friendly" - главное, сделать нормально работающий макрос, а разберётся с ним пользователь, или нет - это уже его проблемы :)  
 
Я правильно понимаю, что нет возможности получить объект типа Range, используя конструкцию [НекаяФункция(параметры)] ?
Не конкретно в том примере, а вообще.  
 
Есть ли такие функции рабочего листа, для которых будет корректна запись  
 
dim ra as range  
set ra = [НекаяФункция(параметры)]
 
{quote}{login=EducatedFool}{date=11.08.2009 08:18}{thema=}{post}Я правильно понимаю, что нет возможности получить объект типа Range, используя конструкцию [НекаяФункция(параметры)] ?
Не конкретно в том примере, а вообще.  
 
Есть ли такие функции рабочего листа, для которых будет корректна запись  
 
dim ra as range  
set ra = [НекаяФункция(параметры)]{/post}{/quote}
Отчего же таких функций несколько. Проблема ведь не в присвоении диапазона функцией, а в создании объединения диапазонов (Union)  
 
Sub test()  
   Set x1 = [INDEX(A:A,1,1)]
   Set x2 = [INDEX((A1:A2,B1:B2),,,2)]
   Set x3 = [INDIRECT("A1:B2")]
   Set x4 = [OFFSET(A1,1,2,5,2)]
   Set x5 = [IF(A1="",A1:B2)]
   Set x6 = [A1:C10 B4:B9]
   Set x7 = [A1:C10:B4:G150]
   Set x8 = [A1:C10,B4:G150,P5]
End Sub  
 
Evaluate и Range работают аналогично, только с текстом:  
 
Sub test2()  
   Set x1 = Range("INDEX(A:A,1,1)")  
   Set x2 = Range("INDEX((A1:A2,B1:B2),,,2)")  
   Set x3 = Range("INDIRECT(""A1:B2"")")  
   Set x4 = Range("OFFSET(A1,1,2,5,2)")  
   Set x5 = Range("IF(A1="""",A1:B2)")  
   Set x6 = Range("A1:C10 B4:B9")  
   Set x7 = Range("A1:C10:B4:G150")  
   Set x8 = Range("A1:C10,B4:G150,P5")  
End Sub  
 
Sub test3()  
   Set x1 = Evaluate("INDEX(A:A,1,1)")  
   Set x2 = Evaluate("INDEX((A1:A2,B1:B2),,,2)")  
   Set x3 = Evaluate("INDIRECT(""A1:B2"")")  
   Set x4 = Evaluate("OFFSET(A1,1,2,5,2)")  
   Set x5 = Evaluate("IF(A1="""",A1:B2)")  
   Set x6 = Evaluate("A1:C10 B4:B9")  
   Set x7 = Evaluate("A1:C10:B4:G150")  
   Set x8 = Evaluate("A1:C10,B4:G150,P5")  
End Sub
KL
 
*  
Фразу "Проблема ведь не в присвоении диапазона функцией, а в создании объединения диапазонов (Union)" следует читать так:  
"Проблема ведь не в присвоении диапазона функцией, а в создании объединения диапазонов на основании условия."(Union)
KL
 
Большое спасибо!  
 
Отныне буду применять эти конструкции, если придумаю, для чего они могут быть полезны.  
Пока вот только ничего не придумал.  
Вот если бы одной строкой кода можно было бы получить объединение диапазонов на основании условия, это помогло бы значительно сократить код.  
 
Тот же OFFSET, как мне кажется, проще записать в виде [a3].offset(x,y)
 
INDEX и INDIRECT - так я пока вообще не знаю, для чего они применяются.  
Буду изучать.  
 
Честно говоря, я думал, что выбор доступных функций намного шире...  
 
 
Кстати, не понял, что возвращает такая функция: Set x1 = Range("A8:C10:F4:D99:E5:h7:a44")  
 
(результат $A$4:$H$99)  
Минимальный диапазон ячеек, в котором содержатся все перечисленные ячейки?
 
{quote}{login=EducatedFool}{date=11.08.2009 09:46}{thema=}{post}Вот если бы одной строкой кода можно было бы получить объединение диапазонов на основании условия, это помогло бы значительно сократить код.{/post}{/quote}  
Можно почти, но проблема в передаче адреса в Range :-(  
 
{quote}{login=EducatedFool}{date=11.08.2009 09:46}{thema=}{post}Тот же OFFSET, как мне кажется, проще записать в виде [a3].offset(x,y){/post}{/quote}
Да, но ошибки генерируются и перехватываются по разному :-) Иногда интереснее это сделать формулой.  
 
{quote}{login=EducatedFool}{date=11.08.2009 09:46}{thema=}{post}INDEX и INDIRECT - так я пока вообще не знаю, для чего они применяются.  
Буду изучать.{/post}{/quote}  
Ну это я так для примера. По сути это эквиваленты Range  
 
{quote}{login=EducatedFool}{date=11.08.2009 09:46}{thema=}{post}Честно говоря, я думал, что выбор доступных функций намного шире...{/post}{/quote}  
Выбор функций, которые можно использовать в таких выражениях - все функции листа :-) Но объект Range возвращают только те, что я показал, так что все остальные должны работать на эти избранные функции. Например:  
Set x1 = [INDEX(A:A,MATCH("x",{""x","y","z"}),1)]
 
{quote}{login=EducatedFool}{date=11.08.2009 09:46}{thema=}{post}Кстати, не понял, что возвращает такая функция: Set x1 = Range("A8:C10:F4:D99:E5:h7:a44")  
 
(результат $A$4:$H$99)  
Минимальный диапазон ячеек, в котором содержатся все перечисленные ячейки?{/post}{/quote}  
Именно! Минимальный прямоугольный диапазон ячеек, в котором содержатся все перечисленные ячейки
KL
 
Так получше будет:  
 
1) "Вот если бы одной строкой кода можно было бы получить объединение диапазонов на основании условия, это помогло бы значительно сократить код."  
 
Можно почти, но проблема в передаче адреса в Range :-(  
 
2) "Тот же OFFSET, как мне кажется, проще записать в виде [a3].offset(x,y)"
 
Да, но ошибки генерируются и перехватываются по разному :-) Иногда интереснее это сделать формулой.  
 
3) "INDEX и INDIRECT - так я пока вообще не знаю, для чего они применяются.  
Буду изучать."  
 
Ну это я так для примера. По сути это эквиваленты Range  
 
4) "Честно говоря, я думал, что выбор доступных функций намного шире..."  
 
Выбор функций, которые можно использовать в таких выражениях - все функции листа :-) Но объект Range возвращают только те, что я показал, так что все остальные должны работать на эти избранные функции. Например:  
Set x1 = [INDEX(A:A,MATCH("x",{""x","y","z"}),1)]
 
5) "Кстати, не понял, что возвращает такая функция: Set x1 = Range("A8:C10:F4:D99:E5:h7:a44")  
 
(результат $A$4:$H$99)  
Минимальный диапазон ячеек, в котором содержатся все перечисленные ячейки?"  
 
Именно! Минимальный прямоугольный диапазон ячеек, в котором содержатся все перечисленные ячейки{/post}{/quote}
KL
 
{quote}{login=KL}{date=11.08.2009 07:50}{thema=Re: Функция: CondRange()}{post}  
Уверен, что ZVI про это знает :-) Для тех же, кто не в курсе:  
данный код имеет ограничение в 8.192 несмежные области ...{/post}{/quote}  
Да, Кирилл, это обсуждалось уже здесь: http://www.planetaexcel.ru/forum.php?thread_id=6627  
Давно это было, лишний раз напомнить не помешает.  
А отвечал-то я знаю кому  - Игорь такие ограничения обойдет и не заметит :-)
Страницы: 1
Читают тему
Наверх