VBA Excel большие данные манипулирование, принимающее навсегда - PullRequest
2 голосов
/ 26 мая 2011

У меня есть два файла Excel.

Первый файл Excel содержит имя и фамилию человека и общее количество дней. Пример.

PersonName       TotalDays
xyz               
abcd             

Другой файл Excel содержит имя, дату и состояние лица (присутствует / отсутствует).

PersonName      Date      Status
xyz           1/1/2011    Present
xyz           1/1/2011    Present

Мне нужно сгруппировать одинаковый статус дат как единое и подсчитать их для обновления в первом файле Excel.

У меня есть около 100 строк в первом файле, где 20000 строк во втором файле, где мне нужноПроверять.Таким образом, чтобы сделать это быстрее, я загрузил все строки из второго файла в массив и считал их для вычисления с каждой записью, которая работает правильно.

Проблема в том, что для Windows требуется много памяти, поэтому в Windows так много приложений автоматическиоткрывается и система почти зависает.

Есть ли альтернатива для реализации этого без проблем с памятью и быстрой обработки.Я сталкивался с Scripting.Dictionary, но не уверен, будет ли он занимать меньше памяти.

EDIT Я пытался использовать redim preserve и статический массив размером 20 000, в обоих случаях возникает одна и та же проблема.

РЕДАКТИРОВАТЬ

lblStatus.Caption = "Loading to memory"
 Dim ArrAuditData() As AData
 Dim TotalLookUpCount As Integer
 For J = 1 To 50000

 If lookUpRange.Cells(J, cmbChoice.ListIndex) = "Fail" Then
  ReDim Preserve ArrAuditData(J) As AData
    ArrAuditData(TotalLookUpCount).AuditType = lookUpRange.Cells(J, cmdAudit2.ListIndex)
    ArrAuditData(TotalLookUpCount).TransTime = lookUpRange.Cells(J, cmbChoice.ListIndex - 1)
    ArrAuditData(TotalLookUpCount).AuditValue = lookUpRange.Cells(J, cmbChoice.ListIndex)
    ArrAuditData(TotalLookUpCount).Slno = lookUpRange.Cells(J, 0)

    TotalLookUpCount = TotalLookUpCount + 1
ElseIf lookUpRange.Cells(J, cmbChoice.ListIndex) = "" And J > 4 Then Exit For

    End If
    DoEvents
  Next

Ответы [ 2 ]

5 голосов
/ 26 мая 2011

Массив из 20 000 элементов, содержащий по 4 варианта, займет менее 2 МБ ОЗУ.Я не думаю, что память имеет какое-либо отношение к вашей проблеме - если только вы не используете старый компьютер с 2 МБ ОЗУ или что-то подобное.

Более вероятная причина, по которой ваш код настолько тяжел, состоит в том, что вы перебираете ячейки.Каждый обмен данными между данными листа VBA и Excel требует значительных издержек, и это складывается, когда вы обращаетесь к нескольким ячейкам по одной за раз.В вашем случае ваш цикл делает до 200 000 отдельных ссылок на ячейки.

Вместо этого вы должны загрузить все свои данные сразу в массив Variant, а затем перебрать этот массив, как показано ниже.Это значительно быстрее (хотя при этом используется больше памяти, а не меньше; но опять же, я не думаю, что память - это ваша проблема).

lblStatus.Caption = "Loading to memory"
Dim ArrAuditData() As AData
Dim varTemp As Variant
Dim TotalLookUpCount As Integer

' Load everything into a Variant array. 
varTemp = lookUpRange

ReDim ArrAuditData(1 To UBound(varTemp, 1)) As AData

For J = 1 To UBound(varTemp, 1)

    If varTemp(J, cmbChoice.ListIndex) = "Fail" Then

        ArrAuditData(TotalLookUpCount).AuditType = varTemp(J, cmdAudit2.ListIndex)
        ArrAuditData(TotalLookUpCount).TransTime = varTemp(J, cmbChoice.ListIndex - 1)
        ArrAuditData(TotalLookUpCount).AuditValue = varTemp(J, cmbChoice.ListIndex)
        ArrAuditData(TotalLookUpCount).Slno = varTemp(J, 0)
        TotalLookUpCount = TotalLookUpCount + 1

    ElseIf varTemp(J, cmbChoice.ListIndex) = "" And J > 4 Then
        Exit For

    End If

    DoEvents
Next

ReDim Preserve ArrAuditData(TotalLookUpCount) As AData

Для дальнейшего чтения взгляните на эту старую, но все еще актуальную статью: http://www.avdf.com/apr98/art_ot003.html

Если вы все еще считаете, что проблема с оперативной памятью, пожалуйста, покажите нам ADataобъявление типа.

РЕДАКТИРОВАТЬ : Кроме того, никогда не ReDim Preserve внутри такого цикла!ReDim Preserve - это очень дорогая операция, и ее редко нужно выполнять более одного раза для любого данного массива.Выполнение этого 20 000 раз замедлит ваш код.Здесь я вынимаю его из цикла и просто использую его один раз в конце, чтобы обрезать неиспользуемые элементы.(Обратите внимание, как я изначально ReDim 'отредактировал массив так, чтобы он соответствовал максимально возможному числу элементов.)

3 голосов
/ 26 мая 2011

Я бы предложил другой подход.

Если я правильно интерпретирую вопрос:

  • Вы хотите получить количество дней, в течение которых каждый человек "присутствует" или "отсутствует"
  • первый файл (назовите его file1) содержит одну строку на человека (около 100 человек)
  • второй файл (назовите его file2) содержит одну строку на человека в день (100 человек и 200 дней = 20000 строк)
  • желаемый результат - два дополнительных столбца в файле 1, представляющих собой счетчик «Присутствующий» и счетчик «Отсутствующий»

Подход, который я бы использовал, заключается в использовании COUNTIF (или если вы используете COUNTIFS в Excel 2007 или более поздней версии)

Пусть

  • file1 содержит таблицу на листе 1 с именем StatusReport, столбцы A = имя, B = присутствует, C = отсутствует
  • одна строка для каждого уникального имени
  • file2 содержит Таблицу на Листе 1 с именем StatusData, столбцы A = Имя, B = Дата, C = Статус
  • одна строка для каждого имени на каждую дату

Решение для Excel 2007 или 2010

  • file1 cell B2
    =COUNTIFS(file2.xlsx!StatusData[Name],[Name],file2.xlsx!StatusData[Status],StatusReport[[#Headers],[Present]])
  • file1 cell C2
    =COUNTIFS(file2.xlsx!StatusData[Name],[Name],file2.xlsx!StatusData[Status],StatusReport[[#Headers],[Absent]])

Решение для Excel 2003

  • Добавить дополнительный столбец D в таблицу fileData2 файла (назовите его Code)
    =Sheet1!$A2&"_"&Sheet1!$C2

  • file1 cell B2
    =COUNTIF([file2.xls]Sheet1!$D:$D,Sheet2!$A2&"_"&Sheet2!$B$1)

  • file1 cell C2
    =COUNTIF([file2.xls]Sheet1!$D:$D,Sheet2!$A2&"_"&Sheet2!$C$1)

Примечание: хотя эти формулы дают тот же результат, версия COUNTIFS + Table ссылается на версию 2010 года, если намного быстрее, это не смешно (мой тест на 300 000 строк обновляется за несколько секунд).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...