Добрый день друзья и коллеги. есть макрос который собирает данные с листов в одномерный массив и выгружает на новый лист. Если значений в массиве <= число строк на листе, то отрабатывает без проблем. А если больше, то не могу победить. Пробовал использовать копию массива (для обрезки и выгрузки частями) - вылетаю в Out of Memory (7). Есть какой способ или придется делать цикл по количеству листов для вывода?
[vba]
Код
Sub Ïåðåáîð() Application.ScreenUpdating = False For Each sh In ActiveSheet.Shapes If sh.AutoShapeType = msoShapeMixed Then If sh.OLEFormat.Object.Value = 1 Then t = t & sh.Name & "|" End If End If Next
arr_sh = Split(t, "|") Dim arr_v() ReDim arr_v(1 To UBound(arr_sh))
For i = 0 To UBound(arr_sh) - 1 With Sheets(arr_sh(i)): arr_v(i + 1) = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)): End With Next i
num = UBound(arr_v) komb = 1
On Error Resume Next For i = 1 To num komb = UBound(arr_v(i)) * komb Next If Err Then Err.Clear On Error GoTo 0
Dim arr_out() ReDim arr_out(1 To komb)
For j = 1 To num o = 1 razd = IIf(j = num, "", "-") On Error Resume Next a = UBound(arr_v(j)) If Err Then a = 1 Err.Clear End If On Error GoTo 0 For i = 1 To komb / a If a > 1 Then For aa = 1 To a arr_out(o) = arr_out(o) & arr_v(j)(aa, 1) & razd o = o + 1 Next Else arr_out(o) = arr_out(o) & arr_v(j) & razd o = o + 1 End If Next i Next j
With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(komb, 1).Value = Application.Transpose(arr_out) .Activate End With Next r Application.ScreenUpdating = True End Sub
[/vba]
upd. наврал про весь лист, при 70000 вылез еще мисматч тут [vba]
Добрый день друзья и коллеги. есть макрос который собирает данные с листов в одномерный массив и выгружает на новый лист. Если значений в массиве <= число строк на листе, то отрабатывает без проблем. А если больше, то не могу победить. Пробовал использовать копию массива (для обрезки и выгрузки частями) - вылетаю в Out of Memory (7). Есть какой способ или придется делать цикл по количеству листов для вывода?
[vba]
Код
Sub Ïåðåáîð() Application.ScreenUpdating = False For Each sh In ActiveSheet.Shapes If sh.AutoShapeType = msoShapeMixed Then If sh.OLEFormat.Object.Value = 1 Then t = t & sh.Name & "|" End If End If Next
arr_sh = Split(t, "|") Dim arr_v() ReDim arr_v(1 To UBound(arr_sh))
For i = 0 To UBound(arr_sh) - 1 With Sheets(arr_sh(i)): arr_v(i + 1) = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)): End With Next i
num = UBound(arr_v) komb = 1
On Error Resume Next For i = 1 To num komb = UBound(arr_v(i)) * komb Next If Err Then Err.Clear On Error GoTo 0
Dim arr_out() ReDim arr_out(1 To komb)
For j = 1 To num o = 1 razd = IIf(j = num, "", "-") On Error Resume Next a = UBound(arr_v(j)) If Err Then a = 1 Err.Clear End If On Error GoTo 0 For i = 1 To komb / a If a > 1 Then For aa = 1 To a arr_out(o) = arr_out(o) & arr_v(j)(aa, 1) & razd o = o + 1 Next Else arr_out(o) = arr_out(o) & arr_v(j) & razd o = o + 1 End If Next i Next j
With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(komb, 1).Value = Application.Transpose(arr_out) .Activate End With Next r Application.ScreenUpdating = True End Sub
[/vba]
upd. наврал про весь лист, при 70000 вылез еще мисматч тут [vba]
sboy, ну так дошли похоже до ограничения, хотя вроде как оспаривается это, но упоминается 65536. Excel 32bit [vba]
Код
Sub test() a = Range("a1:a65536") b = Application.Transpose(a) Debug.Print UBound(b) a = Range("a1:a65537") b = Application.Transpose(a) Debug.Print UBound(b) End Sub
[/vba] 65536 1
На x64 не проверял, надо б переставить, но все лениво как то, а с большими данными не работаю, хватает того что есть.
Ну обойдитесь без транспонирования, работайте с двумерным массивом но с 0 размерностью второго индекса. переделок то всего ничего
[vba]
Код
Sub Ia?aai?() Application.ScreenUpdating = False For Each sh In ActiveSheet.Shapes If sh.AutoShapeType = msoShapeMixed Then If sh.OLEFormat.Object.Value = 1 Then t = t & sh.Name & "|" End If End If Next arr_sh = Split(t, "|") Dim arr_v() ReDim arr_v(1 To UBound(arr_sh))
For i = 0 To UBound(arr_sh) - 1 With Sheets(arr_sh(i)): arr_v(i + 1) = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)): End With Next i
num = UBound(arr_v) komb = 1
On Error Resume Next For i = 1 To num komb = UBound(arr_v(i)) * komb Next If Err Then Err.Clear On Error GoTo 0
Dim arr_out() ReDim arr_out(1 To komb, 0)
For j = 1 To num o = 1 razd = IIf(j = num, "", "-") On Error Resume Next a = UBound(arr_v(j)) If Err Then a = 1 Err.Clear End If On Error GoTo 0 For i = 1 To komb / a If a > 1 Then For aa = 1 To a arr_out(o, 0) = arr_out(o, 0) & arr_v(j)(aa, 1) & razd o = o + 1 Next Else arr_out(o, 0) = arr_out(o, 0) & arr_v(j) & razd o = o + 1 End If Next i Next j
With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(komb, 1).Value = arr_out .Activate End With Next r Application.ScreenUpdating = True End Sub
[/vba]
sboy, ну так дошли похоже до ограничения, хотя вроде как оспаривается это, но упоминается 65536. Excel 32bit [vba]
Код
Sub test() a = Range("a1:a65536") b = Application.Transpose(a) Debug.Print UBound(b) a = Range("a1:a65537") b = Application.Transpose(a) Debug.Print UBound(b) End Sub
[/vba] 65536 1
На x64 не проверял, надо б переставить, но все лениво как то, а с большими данными не работаю, хватает того что есть.
Ну обойдитесь без транспонирования, работайте с двумерным массивом но с 0 размерностью второго индекса. переделок то всего ничего
[vba]
Код
Sub Ia?aai?() Application.ScreenUpdating = False For Each sh In ActiveSheet.Shapes If sh.AutoShapeType = msoShapeMixed Then If sh.OLEFormat.Object.Value = 1 Then t = t & sh.Name & "|" End If End If Next arr_sh = Split(t, "|") Dim arr_v() ReDim arr_v(1 To UBound(arr_sh))
For i = 0 To UBound(arr_sh) - 1 With Sheets(arr_sh(i)): arr_v(i + 1) = Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)): End With Next i
num = UBound(arr_v) komb = 1
On Error Resume Next For i = 1 To num komb = UBound(arr_v(i)) * komb Next If Err Then Err.Clear On Error GoTo 0
Dim arr_out() ReDim arr_out(1 To komb, 0)
For j = 1 To num o = 1 razd = IIf(j = num, "", "-") On Error Resume Next a = UBound(arr_v(j)) If Err Then a = 1 Err.Clear End If On Error GoTo 0 For i = 1 To komb / a If a > 1 Then For aa = 1 To a arr_out(o, 0) = arr_out(o, 0) & arr_v(j)(aa, 1) & razd o = o + 1 Next Else arr_out(o, 0) = arr_out(o, 0) & arr_v(j) & razd o = o + 1 End If Next i Next j
With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(komb, 1).Value = arr_out .Activate End With Next r Application.ScreenUpdating = True End Sub
sboy, можно добавить функции которые будут резать массив на нужное кол-во записей и транспонировать [vba]
Код
Sub test() Dim arr_out(), Arr_OT_DO(), i&, iStep& arr_out = Sheet1.Range("A1:A" & Sheet1.Cells(Rows.Count, 1).End(xlUp).Row) arr_out = TransposeArray_2to1(arr_out) iStep = 100000 ' здесь нужное число строк или activesheet.Rows.count Application.ScreenUpdating = False Dim Start!: Start = Timer For i = LBound(arr_out) To UBound(arr_out) Step iStep Arr_OT_DO = splitArr(arr_out, i, i + iStep - 1) With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(UBound(Arr_OT_DO) + 1, 1).Value = TransposeArray_1to2(Arr_OT_DO) .Cells(UBound(Arr_OT_DO) + 1, 1).Select End With Next Sheet1.Activate Debug.Print "Затрачено: " & Format(Timer - Start, "#0.00") & " сек." Application.ScreenUpdating = True End Sub
Private Function splitArr(ByVal Massiv As Variant, ByVal OT_&, ByVal DO_&) 'режет одномерный массив Dim i&, TmpArr() As Variant If UBound(Massiv) < DO_ Then DO_ = UBound(Massiv) ReDim TmpArr(0 To DO_ - OT_) For i = OT_ To DO_ Step 1 TmpArr(i - OT_) = Massiv(i) Next i splitArr = TmpArr End Function
Function TransposeArray_2to1(ByRef SourceArray() As Variant) As Variant 'Транспонирует из двумерного в одномерный Dim OT_&: OT_ = LBound(SourceArray, 1) Dim DO_&: DO_ = UBound(SourceArray, 1) Dim TempArray As Variant, i& ReDim TempArray(OT_ To DO_) For i = OT_ To DO_ TempArray(i) = SourceArray(i, 1) Next i TransposeArray_2to1 = TempArray End Function
Function TransposeArray_1to2(ByRef SourceArray() As Variant) As Variant 'Транспонирует из одномерного в двумерный Dim OT_&: OT_ = LBound(SourceArray) Dim DO_&: DO_ = UBound(SourceArray) Dim TempArray As Variant, i& ReDim TempArray(OT_ To DO_, 1 To 1) For i = OT_ To DO_ TempArray(i, 1) = SourceArray(i) Next i TransposeArray_1to2 = TempArray End Function
[/vba]
sboy, можно добавить функции которые будут резать массив на нужное кол-во записей и транспонировать [vba]
Код
Sub test() Dim arr_out(), Arr_OT_DO(), i&, iStep& arr_out = Sheet1.Range("A1:A" & Sheet1.Cells(Rows.Count, 1).End(xlUp).Row) arr_out = TransposeArray_2to1(arr_out) iStep = 100000 ' здесь нужное число строк или activesheet.Rows.count Application.ScreenUpdating = False Dim Start!: Start = Timer For i = LBound(arr_out) To UBound(arr_out) Step iStep Arr_OT_DO = splitArr(arr_out, i, i + iStep - 1) With Sheets.Add(after:=Sheets(Sheets.Count)) .Cells(1, 1).Resize(UBound(Arr_OT_DO) + 1, 1).Value = TransposeArray_1to2(Arr_OT_DO) .Cells(UBound(Arr_OT_DO) + 1, 1).Select End With Next Sheet1.Activate Debug.Print "Затрачено: " & Format(Timer - Start, "#0.00") & " сек." Application.ScreenUpdating = True End Sub
Private Function splitArr(ByVal Massiv As Variant, ByVal OT_&, ByVal DO_&) 'режет одномерный массив Dim i&, TmpArr() As Variant If UBound(Massiv) < DO_ Then DO_ = UBound(Massiv) ReDim TmpArr(0 To DO_ - OT_) For i = OT_ To DO_ Step 1 TmpArr(i - OT_) = Massiv(i) Next i splitArr = TmpArr End Function
Function TransposeArray_2to1(ByRef SourceArray() As Variant) As Variant 'Транспонирует из двумерного в одномерный Dim OT_&: OT_ = LBound(SourceArray, 1) Dim DO_&: DO_ = UBound(SourceArray, 1) Dim TempArray As Variant, i& ReDim TempArray(OT_ To DO_) For i = OT_ To DO_ TempArray(i) = SourceArray(i, 1) Next i TransposeArray_2to1 = TempArray End Function
Function TransposeArray_1to2(ByRef SourceArray() As Variant) As Variant 'Транспонирует из одномерного в двумерный Dim OT_&: OT_ = LBound(SourceArray) Dim DO_&: DO_ = UBound(SourceArray) Dim TempArray As Variant, i& ReDim TempArray(OT_ To DO_, 1 To 1) For i = OT_ To DO_ TempArray(i, 1) = SourceArray(i) Next i TransposeArray_1to2 = TempArray End Function
bmv98rus, Спасибо! ограничение обошел, теперь выгружает до 1048576 boa, я похожее и сам пробовал в самом коде с копией массива (ошибка памяти). С помощью Вашей функции 1 лист выгружает, но потом тоже вываливается в ошибку памяти (при втором вызове функции)
bmv98rus, Спасибо! ограничение обошел, теперь выгружает до 1048576 boa, я похожее и сам пробовал в самом коде с копией массива (ошибка памяти). С помощью Вашей функции 1 лист выгружает, но потом тоже вываливается в ошибку памяти (при втором вызове функции)sboy
Вчера не удержался и все ж поставил 2016x64. Как и следовало ожидать ограничение 65536 - осталось. Думаю это сознательно сделано, для совместимости кодов.
Вчера не удержался и все ж поставил 2016x64. Как и следовало ожидать ограничение 65536 - осталось. Думаю это сознательно сделано, для совместимости кодов.bmv98rus
Замечательный Временно просто медведь , процентов на 20.
Application.Transpose - зло и имеет кучу ограничений. Это же аналог старой функции листа. не совсем понял что в первой части кода делается. Но если нужно выгрузить большой одномерный массив на листы то вот: [vba]
Код
Sub d() Dim arr, arr2, i#, shN!, ii&, n#, n2&
n = 4546325
'Create arr: ReDim arr(1 To n) For i = 1 To n: arr(i) = i: Next i = 1
'start loop Do While i <= n n2 = IIf(n - i < Rows.Count - 2, n - i + 1, Rows.Count - 1) arr2 = GetPartArr(arr, i, i + n2 - 1) Sheets.Add after:=Sheets(Sheets.Count) [a2].Resize(UBound(arr2)) = arr2 i = i + n2 Loop End Sub Function GetPartArr(arr, iStart, iFin) ReDim arr2(1 To iFin - iStart + 1, 1 To 1) For i = 1 To UBound(arr2) arr2(i, 1) = arr(iStart + i - 1) Next GetPartArr = arr2 End Function
[/vba] Этот пример выгрузит от 1 до n = 4546325 записей на листы только заметил - похоже на то что boa предложил
Application.Transpose - зло и имеет кучу ограничений. Это же аналог старой функции листа. не совсем понял что в первой части кода делается. Но если нужно выгрузить большой одномерный массив на листы то вот: [vba]
Код
Sub d() Dim arr, arr2, i#, shN!, ii&, n#, n2&
n = 4546325
'Create arr: ReDim arr(1 To n) For i = 1 To n: arr(i) = i: Next i = 1
'start loop Do While i <= n n2 = IIf(n - i < Rows.Count - 2, n - i + 1, Rows.Count - 1) arr2 = GetPartArr(arr, i, i + n2 - 1) Sheets.Add after:=Sheets(Sheets.Count) [a2].Resize(UBound(arr2)) = arr2 i = i + n2 Loop End Sub Function GetPartArr(arr, iStart, iFin) ReDim arr2(1 To iFin - iStart + 1, 1 To 1) For i = 1 To UBound(arr2) arr2(i, 1) = arr(iStart + i - 1) Next GetPartArr = arr2 End Function
[/vba] Этот пример выгрузит от 1 до n = 4546325 записей на листы только заметил - похоже на то что boa предложил SLAVICK
Application.Transpose - зло и имеет кучу ограничений
это я уже понял, в копилку положил Странно, но файл SLAVICK, отрабатывает нормально. Вставил код в свой, вываливает в Out of Memory. Буду копать, чем я оперативку забиваю
Application.Transpose - зло и имеет кучу ограничений
это я уже понял, в копилку положил Странно, но файл SLAVICK, отрабатывает нормально. Вставил код в свой, вываливает в Out of Memory. Буду копать, чем я оперативку забиваю sboy
О! Помогло забытое Erase очистил оперативку от использованного исходного массива и который частично выгружает на лист и заработало [vba]
Код
Erase arr_v '÷èñòèì îïåðàòèâêó Erase arr_v 'чистим оперативку Erase arr_sh 'SLAVIK' i = 1 n = UBound(arr_out) Do While i <= n n2 = IIf(n - i < Rows.Count - 2, n - i + 1, Rows.Count - 1) arr2 = GetPartArr(arr_out, i, i + n2 - 1) Sheets.Add after:=Sheets(Sheets.Count) [a2].Resize(UBound(arr2)) = arr2 Erase arr2 'еще раз чистим i = i + n2 Loop
[/vba]
О! Помогло забытое Erase очистил оперативку от использованного исходного массива и который частично выгружает на лист и заработало [vba]
Код
Erase arr_v '÷èñòèì îïåðàòèâêó Erase arr_v 'чистим оперативку Erase arr_sh 'SLAVIK' i = 1 n = UBound(arr_out) Do While i <= n n2 = IIf(n - i < Rows.Count - 2, n - i + 1, Rows.Count - 1) arr2 = GetPartArr(arr_out, i, i + n2 - 1) Sheets.Add after:=Sheets(Sheets.Count) [a2].Resize(UBound(arr2)) = arr2 Erase arr2 'еще раз чистим i = i + n2 Loop