2016-10-06 5 views
1

У меня есть большой диапазон данных в excel, который я бы хотел проанализировать в массиве для определенной пользователем функции. Диапазон 2250 х 2250. Это занимает слишком много времени, чтобы разобрать каждую ячейку с помощью для цикла, и он слишком велик, чтобы быть назначено на массив с помощью этого метода:Самый эффективный способ синтаксического анализа большого массива в массиве VBA

dim myArr as Variant 
myArr = range("myrange") 

Просто мозговой атаки здесь, будет его быть более эффективным для анализа в каждом столбце и объединения массивов? Есть идеи?

Thanks

+1

Я просто установил книгу с данными в диапазоне от a1 до chn2250 (диапазон 2250X2250) и прочитал ее в альтернативном массиве под названием «x», используя «x = range (« a1: chn2250 »). Value2' then just to to убедитесь, что это сработало, 'debug.print x (2,2)'. Вся операция заняла менее секунды. Итак, я бы предложил вариант массива. – Kyle

+1

Попробуйте добавить '.Value' или' .Value2', поскольку @Kyle предложил то, что у вас было выше. –

+0

Я явно не указал «.Value2», но это ускоритель производительности. – Kyle

ответ

4

Вы почти у цели.

код вам нужно:

Dim myArr as Variant 
myArr = range("myrange").Value2 

Обратите внимание, что я использую .Value2 свойство диапазона, а не только «Value», который читает форматы и региональные настройки, и, вероятно, искажать любые даты

Обратите внимание, что я не побеспокоил Redim и указал размеры массива: свойства Value и Value2 являются двумерным массивом (от 1 до Rowcount, от 1 до Col Count) ... Если это не так, одна ячейка, которая будет скалярным вариантом, который разбивает любой нисходящий код, ожидающий массив. Но это не ваша проблема с известным диапазоном 2250 x 2250.

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

Общий принцип заключается в том, что каждое «попадание» на рабочий лист занимает около двадцатого секунды - некоторые машины работают намного быстрее, но все они имеют плохие дни - и «удар» или чтение одной ячейки переменной почти точно совпадает с чтением диапазона в семь миллионов ячеек в массив вариантов. Оба значения равны миллионам раз быстрее, чем чтение этого диапазона в одной ячейке за раз.

В любом случае вы можете рассчитывать на любую операцию в VBA, как это происходит в нулевое время после того, как вы выполнили «чтение» и перестали взаимодействовать с рабочим листом.

Цифры все очень грубые и готовые, но общие принципы будут выполняться вплоть до момента, когда вы начнете выделять массивы, которые не будут вписываться в рабочую память, и, опять же, это не ваша проблема сегодня.

Вспомните Erase вариант массива, когда вы закончили, вместо того, чтобы полагаться на него, выходит за рамки: это будет иметь значение с диапазоном этого размера.

+0

Привет, Нил, Большое спасибо за подробное объяснение. Я не думал использовать Value2, и кажется, что он должен работать. Однако я могу работать в объеме памяти. Макрос теперь ломается, говоря, что он не в памяти. Размер листа составляет 70 кб, поскольку каждая ячейка в матрице имеет функцию. Есть ли другие рекомендации, которые вы можете сделать для меня? Если нет, я могу попытаться удалить некоторую избыточную информацию. – Daniel

+0

@ Daniel - Является ли макрос нарушающим выражение 'arr = Range.Value2'? Существует ограничение на то, что вы можете сделать, но объявление переменной объекта диапазона и использование этого может помочь; как будет установлено 'Application.Calculation = xlCalculationManual' –

+0

@ Daniel - если эти шаги не решают проблему, следующим шагом будет удаление массива вручную, а затем передать значение диапазона:' Redim arr (1 to rng. Rows.Count, 1 - rng.Columns.Count', а затем попробуйте 'arr = rng.Value2' ... И шаг после *, который * должен загрузить диапазон в кусках - либо тысяча строк, либо тысяча или столбцы в время. Также: вы * используете * опцию Option.Explicit или параметр Require Requireable Declaration в VBA? –

1

Это прекрасно работает.

Sub T() 
    Dim A As Variant 

    A = Range("A2").Resize(2250, 2250).Value2 

    Dim i As Long, j As Long 
    For i = 1 To 2250 
     For j = 1 To 2250 
      If i = j Then A(i, j) = 1 
     Next j 
    Next i 

    Range("A2").Resize(2250, 2250).Value2 = A 
End Sub 
+0

Спасибо, это интересный трюк! ... Можете ли вы проверить, объявляет ли переменную Range, устанавливая ее в диапазон монстров, а также заполняет массив из этой переменной диапазона? Эта ошибка может быть зависящей от машины, но ближайшая причина заключается в том, что VBA делает дикие догадки о памяти, которую нужно выделить, когда пытается интерпретировать «Range ([некоторая строка, которую мы будем анализировать во время выполнения]) .Value2' вместо хорошо управляемый объект с VTable или (как вы показали нам) функцию возврата диапазона с четко определенным размером. –

+0

Как 'Set r = Range (" .. "). Resize (..)', а затем 'vals = r.Values2'? Это то же самое, что и выше. – ja72

+0

- Не совсем. Что касается кода *, который предполагается *, оба подхода одинаковы. Но является ли компилятор (и поведение во время выполнения) достаточно умным, чтобы распознать, что ваш объект диапазона r имеет известные размеры во время компиляции? Или это реализация для чтения измерений переменной диапазона, различной (менее вероятно, чтобы делать дикие догадки и переоценивать при распределении памяти) механизму для его считывания из метода Range с произвольной адресной строкой? –

0

Я думаю, что лучшие варианты:

  1. Попробуйте ограничить данные для разумного количества, скажем 1,000,000 значения в то время.
  2. Добавьте ошибку обработки ошибок, чтобы поймать ошибку Out of Memory, а затем повторите попытку, но уменьшите размер пополам, затем на треть, четверть и т. Д. ... пока это не сработает.

В любом случае, если мы используем наборы данных порядка 5 000 000 значений, и вы хотите убедиться, что программа будет работать, вам нужно будет отрегулировать код, чтобы обрезать данные.

Смежные вопросы