Страницы: 1
RSS
Удалить строку двумерного массива
 
Есть массив arr(100,3). Хочу удалить 30 строку. Как это сделать?  
Спасибо.
 
Есть вариант удалить строку на листе, а потом записать в массив.  
Но можно как-то программно?
 
{quote}{login=PavelKs}{date=12.11.2010 10:59}{thema=}{post}удалить строку на листе, а потом записать в массив.  
как-то программно{/post}{/quote}  
'  
Sub Удалить_Строку_30()  
   Dim Sh As Worksheet, Arr() As Variant, Rng As Range  
   '  
   ReDim Arr(1 To 100, 1 To 3)  
   Application.ScreenUpdating = False  
   Application.DisplayAlerts = False  
   Set Sh = ThisWorkbook.Worksheets.Add  
   Set Rng = Sh.Range("A1").Resize(100, 3)  
   Rng.Value = Arr  
   Sh.Rows(30).Delete  
   Arr = Rng.Resize(99).Value  
   Sh.Delete  
   Application.DisplayAlerts = True  
   Application.ScreenUpdating = True  
End Sub
 
А, например, вот так:  
Sub Del_Arr_RC(Arr(), Optional iRow& = 0, Optional iCol& = 0) 'удалить из массива любую строку и/или столбец  
  Dim L1&, U1&: L1 = LBound(Arr, 1): U1 = UBound(Arr, 1)  
  Dim L2&, U2&: L2 = LBound(Arr, 2): U2 = UBound(Arr, 2)  
  Dim TempSh As Worksheet, Rng As Range  
  Application.ScreenUpdating = False: Application.DisplayAlerts = False  
  Set TempSh = ThisWorkbook.Worksheets.Add  
  Set Rng = Cells(1, 1).Resize(U1 - L1 + 1, U2 - L2 + 1)  
  Rng.Value = Arr  
  If iRow > 0 And iRow <= U1 - L1 + 1 Then Rows(iRow).Delete  
  If iCol > 0 And iCol <= U2 - L2 + 1 Then Columns(iCol).Delete  
  Arr = Rng.Resize(U1 - L1 + 1 + (iRow > 0), U2 - L2 + 1 + (iCol > 0)).Value  
  TempSh.Delete  
  Application.ScreenUpdating = True: Application.DisplayAlerts = True  
End Sub  
 
Надо будет ещё попробовать найти время и доработать:  
- не на временном листе делать, а во временной книге  
- чтобы можно было число строк/столбцов задавать.
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Вот так по-корректнее будет: делать в новой книге, тогда даже если текущая книга защищена, то не будет ошибки  
Sub Del_Arr_RC(Arr(), Optional xRow& = 0, Optional xCol& = 0)   'удалить из массива любую строку и/или столбец  
  Dim L1&, U1&: L1 = LBound(Arr, 1): U1 = UBound(Arr, 1)  
  Dim L2&, U2&: L2 = LBound(Arr, 2): U2 = UBound(Arr, 2)  
  Dim tmpWBk As Workbook, tmpRng As Range  
  Application.ScreenUpdating = False: Application.DisplayAlerts = False  
  Set tmpWBk = Application.Workbooks.Add  
  Set tmpRng = Cells(1, 1).Resize(U1 - L1 + 1, U2 - L2 + 1)  
  tmpRng.Value = Arr  
  If xRow > 0 And xRow <= U1 - L1 + 1 Then Rows(xRow).Delete  
  If xCol > 0 And xCol <= U2 - L2 + 1 Then Columns(xCol).Delete  
  Arr = tmpRng.Resize(U1 - L1 + 1 + (xRow > 0), U2 - L2 + 1 + (xCol > 0)).Value  
  tmpWBk.Close: Set tmpWBk = Nothing: Set tmpRng = Nothing  
  Application.ScreenUpdating = True: Application.DisplayAlerts = True  
End Sub
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Ну, и чтобы закрыть тему:  
Function DelArrRC(Arr(), Optional xRow& = 0, Optional xCol& = 0)   'удалить из массива любую строку и/или столбец  
  ' работает во временном новом листе текущей книги. При защите структуры или общем доступе к книге могут быть сбои.  
  Dim L1&, U1&: L1 = LBound(Arr, 1): U1 = UBound(Arr, 1)  
  Dim L2&, U2&: L2 = LBound(Arr, 2): U2 = UBound(Arr, 2)  
  Dim tmpSh As Worksheet, tmpRng As Range  
  Application.ScreenUpdating = False: Application.DisplayAlerts = False  
  Set tmpSh = ThisWorkbook.Worksheets.Add  
  Set tmpRng = Cells(1, 1).Resize(U1 - L1 + 1, U2 - L2 + 1)  
  tmpRng.Value = Arr  
  If xRow > 0 And xRow <= U1 - L1 + 1 Then Rows(xRow).Delete  
  If xCol > 0 And xCol <= U2 - L2 + 1 Then Columns(xCol).Delete  
  DelArrRC = tmpRng.Resize(U1 - L1 + 1 + (xRow > 0), U2 - L2 + 1 + (xCol > 0)).Value  
  tmpSh.Delete: Set tmpSh = Nothing: Set tmpRng = Nothing  
  Application.ScreenUpdating = True: Application.DisplayAlerts = True  
End Function  
 
Function DelArrRC_0(Arr(), Optional xRow& = 0, Optional xCol& = 0)   'удалить из массива любую строку и/или столбец  
  ' работает во временной новой книге - чуть медленнее, но не волнует защита структуры книги или общий доступ  
  Dim L1&, U1&: L1 = LBound(Arr, 1): U1 = UBound(Arr, 1)  
  Dim L2&, U2&: L2 = LBound(Arr, 2): U2 = UBound(Arr, 2)  
  Dim tmpWBk As Workbook, tmpRng As Range  
  Application.ScreenUpdating = False: Application.DisplayAlerts = False  
  Set tmpWBk = Application.Workbooks.Add  
  Set tmpRng = tmpWBk.Sheets(1).Cells(1, 1).Resize(U1 - L1 + 1, U2 - L2 + 1)  
  tmpRng.Value = Arr  
  If xRow > 0 And xRow <= U1 - L1 + 1 Then tmpRng.Rows(xRow).Delete  
  If xCol > 0 And xCol <= U2 - L2 + 1 Then tmpRng.Columns(xCol).Delete  
  DelArrRC_0 = tmpRng.Resize(U1 - L1 + 1 + (xRow > 0), U2 - L2 + 1 + (xCol > 0)).Value  
  tmpWBk.Close: Set tmpWBk = Nothing: Set tmpRng = Nothing  
  Application.ScreenUpdating = True: Application.DisplayAlerts = True  
End Function
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
{quote}{login=PavelKs}{date=12.11.2010 10:59}{thema=}{post}Есть вариант удалить строку на листе, а потом записать в массив.  
Но можно как-то программно?{/post}{/quote}  
 
можно и так переписать из массива в массив (как вариант)  
Sub arrdel_str()  
arr = Range("A1:B5").Value  
Dim delStr&, x&  
ReDim arrf(1 To 4, 1 To 2)  
delStr = 3: x = 1  
   For i = 1 To UBound(arr)  
      If i <> delStr Then arrf(x, 1) = arr(i, 1): arrf(x, 2) = arr(i, 2): x = x + 1  
   Next i  
Range("C1:D4") = arrf  
End Sub
Спасибо
 
Дмитрий, ты, конечно, прав...  
Просто по инерции мышления: как начали тут делать с диапазоном, так я и продолжил...  
Конечно, с массивом намного универсальнее и быстрее в несколько раз получается.  
Я свою предыдущую универсальную (любые размерности массивов и сразу строку и столбец можно задавать) формулу подпилил.  
На массиве 100х100 выигрыш в скорости получился в 5 раз.  
 
Function DelArrRC(Arr(), Optional xRow& = 0, Optional xCol& = 0)   'удалить из массива любую строку и/или столбец  
  Dim L1&, U1&: L1 = LBound(Arr, 1): U1 = UBound(Arr, 1)  
  Dim L2&, U2&: L2 = LBound(Arr, 2): U2 = UBound(Arr, 2)  
  Dim tArr(): ReDim tArr(L1 To U1 + (xRow > 0), L2 To U2 + (xCol > 0))  
  Dim RR&, CC&, tRR&, tCC&  
  tRR = L1  
  For RR = L1 To U1  
     tCC = L2  
     If RR <> xRow Then  
        For CC = L2 To U2  
           If CC <> xCol Then: tArr(tRR, tCC) = Arr(RR, CC): tCC = tCC + 1  
        Next  
        tRR = tRR + 1  
     End If  
  Next  
  DelArrRC = tArr  
End Function
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Alex_ST, R Dmitry, Спасибо.  
R Dmitry, подошел Ваш вариант.
 
{quote}{login=PavelKs}{date=15.11.2010 06:48}{thema=}{post}Alex_ST, R Dmitry, Спасибо.  
R Dmitry, подошел Ваш вариант.{/post}{/quote}  
Ну и ладненько, пользуйтесь на здоровье.
Спасибо
 
Конечно, пользуйтесь макросом Дмитрия...  
Он намного короче.  
Но "заточен" на строго определённый конкретный случай.  
Правда, если послезавтра вам нужно будет удалять не 30-ю строку, а 23-й столбец из массива другой размерности, будете опять обращаться за помощью на форум или самостоятельно перелопачивать макрос.  
Я же всё-таки предпочитаю писать и потом использовать универсальные макросы с задаваемыми аргументами и минимумом ограничений на их значения. Самому же потом проще: взял из своей "копилки" подходящий макрос и, не переделывая, вставил в требуемый модуль.  
:-)
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Alex_ST, Ваш в копилке. Спасибо.  
R Dmitry'я, в работе. :)
 
Просто на всякий случай полезный совет из личного опыта:  
при работе с массивами я предпочитаю при задании размерностей указывать не только UBound, но и LBound чтобы от значения Option Base 1/0 не зависели результаты работы макросов.  
И именно поэтому я в своих макросах для обработки массивов всегда делаю циклы от LBound до UBound. Да и разноразмерные массивы при этом всегда корректно обрабатываются
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Alex_ST, спасибо, это я заметил - именно по этому и в копилке.  
Загляните в http://www.planetaexcel.ru/forum.php?thread_id=21342. Спасибо.
 
traspose и получим столбец  
:)
Спасибо
 
R Dmitry, и Вас просу заглянуть  
http://www.planetaexcel.ru/forum.php?thread_id=21342
 
{quote}{login=R Dmitry}{date=15.11.2010 01:13}{thema=Re: }{post}{quote}{login=PavelKs}{date=12.11.2010 10:59}{thema=}{post}Есть вариант удалить строку на листе, а потом записать в массив.  
Но можно как-то программно?{/post}{/quote}  
 
можно и так переписать из массива в массив (как вариант)  
Sub arrdel_str()  
arr = Range("A1:B5").Value  
Dim delStr&, x&  
ReDim arrf(1 To 4, 1 To 2)  
delStr = 3: x = 1  
   For i = 1 To UBound(arr)  
      If i <> delStr Then arrf(x, 1) = arr(i, 1): arrf(x, 2) = arr(i, 2): x = x + 1  
   Next i  
Range("C1:D4") = arrf  
End Sub{/post}{/quote}  
 
уточню :)  
 
Sub arrdel_str(rng as range)  
arr = rng  
Dim delStr&, i&, j&, mr&  
delStr = 3: x = 1: mr = UBound(arr)  
ReDim arrf(1 To mr - delStr + 1, 1 To UBound(arr, 2))  
   For i = 1 To mr - delStr  
       For j = 1 To UBound(arr, 2)  
           arrf(i, j) = arr(i + delStr, j)  
       Next  
   Next i  
rng(delstr).Resize(UBound(arrf), UBound(arr, 2)) = arrf  
End Sub
Живи и дай жить..
 
но можно еще быстрее - цикл copymemory по столбцам
Живи и дай жить..
 
{quote}{login=слэн}{date=16.11.2010 11:13}{thema=}{post}но можно еще быстрее - цикл copymemory по столбцам{/post}{/quote}  
Буду признателен за небольшой пример
 
слэн,  
на сколько я понял, delStr - это не число удаляемых строк, а номер удаляемой строки (иначе нужно было бы ещё и задавать, с какой начиная нужно удалять)  
Поэтому я и писАл:    
Dim tArr(): ReDim tArr(L1 To U1 + (xRow > 0), L2 To U2 + (xCol > 0))
С уважением, Алексей (ИМХО: Excel-2003 - THE BEST!!!)
 
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)  
Sub arrdel_str_copymem()  
arr = Range("A1:B5").Value  
Dim delStr&, j&, mr&  
delStr = 3:  mr = UBound(arr)  
       For j = 1 To UBound(arr, 2)  
           CopyMemory arr(delStr, j), arr(delStr + 1, j), 16 * (mr - delStr)  
           arr(mr, j) = Empty  
       Next  
End Sub
Живи и дай жить..
 
слэн, спасибо, буду разбираться.
 
{quote}{login=Alex_ST}{date=16.11.2010 11:29}{thema=}{post}слэн,  
на сколько я понял, delStr - это не число удаляемых строк, а номер удаляемой строки (иначе нужно было бы ещё и задавать, с какой начиная нужно удалять)  
Поэтому я и писАл:    
Dim tArr(): ReDim tArr(L1 To U1 + (xRow > 0), L2 To U2 + (xCol > 0)){/post}{/quote}  
 
да, там я неправильно понял, сделал именно для выгрузки на лист.  
последний пример лучше( и необязательно с copymem)
Страницы: 1
Читают тему
Наверх