Страницы: 1
RSS
Обработка большого количества строк макросом, перебор строк + транспонирование
 
Добрый день.

Прошу помощи или совета как действовать.
Ко мне попадает файл (как в примере), он постоянно обновляется и мне нужно почти каждый день приводить из состояния "Исходник" в "то что нужно". Сейчас в файле уже больше 100 000 строк. К концу года будет более 500 000.
Я разворачивал в нужный мне вид привязываясь к отступам каждой строки (цикл по строкам, больше цифра отступа - больше номер колонки). Но уже сейчас этот процесс занимает довольно продолжительное время.
Каким способом можно ускорить получение результата?
 
Вопросы:
1. Можно ли привязываться к группе значений в столбце В? Они одинаковые в пределах группы?
2. Всегда ли в группе 10 строк?
 
Непонятно почему одинаковые цифры и по порядку. Почему?
Получить такой результат легко просто перекладывая из одного массива в другой, всего один цикл. Но подозреваю что не так всё просто.
И какая может быть длина текстов?

P.S. Юрий опередил... Да и про 10 строк тоже конечно нужно спросить :)
А если там вообще никакой системы нет - то словарь с коллекциями!
Изменено: Hugo - 13.05.2016 20:09:36
 
У меня проглядывается алгоритм массив + коллекция))
Точнее, два массива: один с исходными данными, другой для выгрузки.
 
Я стандартно - данные в массив, один цикл по нему - к каждому ключу из B собираем коллекцию из "оттриммленных" A. Параллельно смотрим какая будет максимальная коллекция.
В финале можно прямо так построчно и выгружать циклом по словарю, или создать массив под результат, переложить, выгрузить.
Но конечно на 100000 строк быстро не будет, где-то может даже до минуты, смотря какая машина.
 
Если в блоке всегда по 10 строк, то задача, на мой взгляд, упрощается: не нужно вычислять количество столбцов массива для выгрузки.
 
Доброе время суток
Цитата
Юрий М написал:
Если в блоке всегда по 10 строк, то задача, на мой взгляд, упрощается: не нужно вычислять количество столбцов массива для выгрузки.
Если я правильно понял первичный ключ (rowId, colId), то можно, думаю, обойтись только двумя массивами. Только, полагаю, там не на столь простая структура.
 
Андрей, задумка понятна. Но я немного о другом: если НЕИЗМЕННО количество строк в каждом блоке. Т.е. везде одинаково ))
 
Цитата
Юрий М написал: если НЕИЗМЕННО количество строк в каждом блоке.
Хе, хе, Юрий, как полагаю, сейчас придёт ТС и скажет, что всё чуть-чуть не так (Упростил - думал дальше сам разберусь :D ). В блоке не фиксированное число строк, после отступа 2 могут подряд идти от одного до десяти с отступом 3 (а куда их тогда девать? Ждём-с.
 
Цитата
Андрей VG написал:
полагаю, сейчас придёт ТС и скажет, что всё чуть-чуть не так (Упростил - думал дальше сам разберусь
Чаще всего так оно и бывает )
 
Цитата
Юрий М написал: Но я немного о другом: если НЕИЗМЕННО количество строк в каждом блоке. Т.е. везде одинаково ))
Количество строк в каждом блоке одинаковое, но внутри может быть разное.
Т.е. куча таких блоков по 5 строк в каждом, или по 6, или по 7.
Столбец с суммами справа (иногда их 2, но думаю это я и сам смогу дописать опираясь на ваш пример, поэтому не уточнял)
Т.е. структура отчетов точно такая, как в примере, только количество строк в блоках "плавающее".
Цитата
Hugo написал: Непонятно почему одинаковые цифры и по порядку. Почему?
Цифры по порядку просто для примера. Там суммы платежей будут.
Цитата
Андрей VG написал: после отступа 2 могут подряд идти от одного до десяти с отступом 3 (а куда их тогда девать?
Отступы всегда идут по нарастающей (в рамках одного блока). Т.е. нет подряд строк с одинаковыми отступами.
 
Цитата
lis2109 написал:
Цифры по порядку просто для примера. Там суммы платежей будут.
А тогда что нужно получить в столбце Р для группы? Сумму по группе?
 
Цитата
А тогда что нужно получить в столбце Р для группы? Сумму по группе?
А точно, не сказал.
В каждом блоке, напротив каждого текста повторяется одна и та же сумма.
Т.е. каждый блок - это информация об одном платеже. Ее нужно развернуть в горизонтальное положение.
Еще раз пример прикрепил, посмотрите.
Т.е. сумму из каждого блока нужно взять только один раз.
Изменено: lis2109 - 13.05.2016 21:08:36
 
Судя по примеру 2, у вас, как предположил Юрий, в каждом блоке одинаковое число строк. Тогда
1.По первому столбцу со второй строки пробегаем и подсчитываем сколько строк в блоке
Код
Public Function GetBlockRowCount(ByVal forColumn As Range) As Long
    Dim vCount As Long, i As Long
    vCount = 1: i = 2
    Do Until forColumn.Cells(i, 1).IndentLevel = 0
        vCount = vCount + 1
    Loop
    GetBlockRowCount = vCount
End Function

2.Далее считываем сразу весь массив в память
3.Определяем число строк в этом массиве и столбцов
4.Создаём массив вывода числом строк = 3. / GetBlockRowCount и столбцов GetBlockRowCount + число столбцов в исходном - 1
5.Циклом с шагом GetBlockRowCount пробегаем исходный и переписываем в массив вывода (естественно, пересчитывая индексы)
Как-то так
Изменено: Андрей VG - 13.05.2016 21:22:25 (Код поправил должно было быть forColumn.Cells(i, 1).IndentLevel = 0)
 
Спасибо.
С массивами знаком очень слабо, поэтому получилось как-то так:
Код
Public Function GetBlockRowCount(ByVal forRows As Long, ByVal forColumn As Long) As Long
    Dim vCount As Long, i As Long
    vCount = 1
    i = forRows
    Do Until Cells(i, forColumn).IndentLevel = 0
        i = i + 1
        vCount = vCount + 1
    Loop
        GetBlockRowCount = vCount
End Function

Sub test()
    t = Timer
  Dim первая_строка As Long: первая_строка = 3
  Dim колонка_с_текстом As Long: колонка_с_текстом = 1
  Dim колонка_с_суммой As Long: колонка_с_суммой = 2
    
    количество_строк_в_блоке = GetBlockRowCount(первая_строка, колонка_с_текстом)
         
Dim lLastRow As Long
    lLastRow = ActiveSheet.Cells(Rows.Count, колонка_с_текстом).End(xlUp).Row
   
   Dim massivStr() As String
   Dim massivLng_1() As Long
   Dim massivLng_2() As Long
    ReDim massivStr(lLastRow)
    ReDim massivLng_1(lLastRow)
    ReDim massivLng_2(lLastRow)
      первая_строка = первая_строка - 1
       
   Dim i As Long
     For i = первая_строка To lLastRow
         massivStr(i - первая_строка) = Cells(i, колонка_с_текстом)
         massivLng_1(i - первая_строка) = Cells(i, колонка_с_суммой)
         massivLng_2(i - первая_строка) = Cells(i, колонка_с_суммой + 1)
     Next i
       
Dim j As Long
    j = 1
Dim k As Long
    k = 1
   
   For i = первая_строка To lLastRow
        Sheets("Лист2").Cells(k, j) = massivStr(i - первая_строка)
        j = j + 1
        If j - 1 = количество_строк_в_блоке Then
           Sheets("Лист2").Cells(k, количество_строк_в_блоке + 1) = massivLng_1(i - первая_строка)
           Sheets("Лист2").Cells(k, количество_строк_в_блоке + 2) = massivLng_2(i - первая_строка)
           j = 1
           k = k + 1
        End If
   Next i
       MsgBox t
End Sub
В файле (https://yadi.sk/d/UkZqbPlhriDUG) пример на 700 тыс.строк.
Массивы не очень ускорили работу.
Скорее всего я что-то напортачил в коде.
Подскажите, пожалуйста, по оптимизации.
 
Цитата
lis2109 написал: Массивы не очень ускорили работу.
У меня ускорились.
Возможно я не полностью вник в суть, но пробовал так
Код
Private Sub Start()
    Dim Sh As Worksheet
    Set Sh = ThisWorkbook.Worksheets(1)
    LastRow = Sh.Cells(Sh.Rows.Count, 1).End(xlUp).Row
    Debug.Print Now
    Dim первая_строка As Long: первая_строка = 3
  Dim колонка_с_текстом As Long: колонка_с_текстом = 1
  Dim колонка_с_суммой As Long: колонка_с_суммой = 2
     
    количество_строк_в_блоке = GetBlockRowCount(первая_строка, колонка_с_текстом)
    dx = Sh.Range("A2:C" & LastRow)
    Count = UBound(dx) / количество_строк_в_блоке
    ReDim X(1 To Count, 1 To количество_строк_в_блоке + 2)
    Count = 0
    For n = 1 To UBound(dx) Step количество_строк_в_блоке
        Count = Count + 1
        For i = 0 To количество_строк_в_блоке - 1
            X(Count, i + 1) = dx(i + n, колонка_с_текстом)
        Next
        X(Count, 11) = dx(количество_строк_в_блоке - 1 + n, 2)
        X(Count, 12) = dx(количество_строк_в_блоке - 1 + n, 3)
    Next
   Sheets("Лист2").Range("A1").Resize(Count, количество_строк_в_блоке + 2) = X
    Debug.Print Now

End Sub

Результат
15.05.2016 1:09:18
15.05.2016 1:09:23
Изменено: Doober - 15.05.2016 02:13:08
 
Доброе время суток
Сергей, какое у вас "железо", что за 5 сек? У меня на "монстре" Lenovo U165 быстрее 10сек не вышло.
lis2109, как то вы отошли совсем в другую сторону от предложенного алгоритма.
Скрытый текст

Успехов
 
Андрей, совсем скромное.
Диск  samsung SSD 850 EVO 120
 
Цитата
Doober написал:
совсем скромное.
Сергей, спасибо за информацию. Как раз в два раза по производительности и расходимся.
 
lis2109, не ужели не один из предложенных вариантов не подошёл? Смотрю мимо ходите. :)
 
Стыдно признаться, но что-то я даже не смог запустить процедуру CreateTransposed )
 
Да всё просто. Ей нужен параметр  - ссылка на лист :)
Код
CreateTransposed ActiveSheet
например
 
Спасибо.
А я уж и так и сяк перепробовал, и все ошибку выдавало.
"а ларчик просто открывался" ))

Да, ваш вариант на моем компе выполнил работу почти в 3 раза быстрее, чем вариант, который я смастерил.
Еще раз спасибо.
Страницы: 1
Наверх