Новости:

К первому сообщению темы должен быть прикреплен файл примера в формате xls*.
Приложив пример, Вы избавите себя и других от вопросов типа "А какой критерий?", "А куда выводить результат?", "А сколько строк?" и все тех же просьб выложить файл. Рисовать за Вас Ваши же таблички с заданиями, а затем и решение к ним, никто желанием не горит. Да и, как показывает практика, в большинстве случаев без файла решения не найти.

Главное меню

Как распечатать массив в таблицу?

Автор Олег*, 30.04.2013, 18:33

« назад - далее »

Олег*

Добрый день!

Снова обращаюсь за помощью к уважаемым членам клуба знатоков Экселя.

Задача состоит в следующем (разумеется, реальная задача гораздо сложнее, но я упростил, чтобы разобраться именно в интересующем меня моменте).
На Листе1 имеются 4 ячейки: Время, Число1, Число2 и Сумма.

Макрос последовательно (в цикле) пробегает по всем значениям Число1 и Число2 в определенных диапазонах.
Разумеется в ячейке Сумма каждый раз вычисляется сумма каждой новой пары слагаемых, а в ячейку Время макрос вставляет время,  когда была произведена данная операция.

Требуется.
Распечатать в таблицу все результаты, т.е. иными словами, дать развертку во времени.

Разумеется, в приведенном (упрощенном) примере скорость работы программы не критична,  но в реальной разработке приходится ждать очень долго. Поэтому захотелось оптимизировать следующим образом: мы не копируем полученные строчки в таблицу по ходу выполнения макроса, а создаем массив данных, в котором содержатся все полученные строчки будущей таблицы, а потом одномоментно "выплескиваем" полученную таким образом таблицу в то место, где она должна быть.

Private Sub CommandButton1_Click()
  Dim I As Long
  Dim J As Long
  Dim СтрокаТаблицы As Long
  Dim массВсяТаблицаЦеликом() As Variant
 
  Application.ScreenUpdating = False
      ReDim массВсяТаблицаЦеликом(1500)
   
        For I = 1 To 100
            For J = 1 To 10
                [Число1] = I
                [Число2] = J
                [Время] = Time
               
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
                массВсяТаблицаЦеликом(СтрокаТаблицы) = [ВсяСтрокаДанных].Value
            Next J
        Next I
       
        'Распечатка всего массива в таблицу.
        Range("G2:J" & (СтрокаТаблицы + 1)) = массВсяТаблицаЦеликом()
    Application.ScreenUpdating = True
   
    MsgBox "Обработка данных завершена, таблица заполнена :)"
End Sub


Проблема в том, что итоговавя таблица отказывается распечатываться, хотя массив в памяти создан:



Помогите, пожалуйста, разобраться в чем проблема.











Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Hugo121

Нужно делать иначе - сразу брать все данные в массив, затем его перебирать/обрабатывать, затем выгружать  результат на лист.
И чтоб удобнее/быстрее выгружать - массив должен быть двумерным. У Вас сейчас одномерный.
Toncoin (TON):
UQAUV5ZpXnNQ4JYt9fOI-rtgGw9-ZSFqRqynDzp5cZcoh5GC

Олег*

Цитата: Hugo121 от 30.04.2013, 20:17
Нужно делать иначе - сразу брать все данные в массив, затем его перебирать/обрабатывать, затем выгружать  результат на лист.

Я это прекрасно знаю, но в данном случае так не получится. Все дело в том, что у меня львиную долю работы делают именно встроенные в рабочие листы функции. Я не могу взять весь этот сложный механизм в макрос. Точнее говоря, могу сделать нечто подобное, но будет работать гораздо медленнее. Поэтому у меня для доступа есть только несколько ячеек, значениями которых я могу "играть". В смысле, вставляю данные в эти исходные ячейки, потом Эксель с помощью встроенных функций их обрабатывает и в одной из ячеек выдает мне результат.

Таблица нужна для просмотра и анализа всех исходных и конечных значений.
Я не знаю, как лучше это объяснить. Но одним словом, не могу взять все данные сразу в массив. Могу взять только исходные данные и полученное значение в ячейке с результатом. Для удобства считывания в массив располагаю эти ячейки в одной строчке.

Цитата: Hugo121 от 30.04.2013, 20:17
И чтоб удобнее/быстрее выгружать - массив должен быть двумерным. У Вас сейчас одномерный.

Сейчас попробовал сделать вот так:

Private Sub CommandButton1_Click()
  Dim I As Long
  Dim J As Long
  Dim СтрокаТаблицы As Long
  Dim массВсяТаблицаЦеликом() As Variant
 
  Application.ScreenUpdating = False
      ReDim массВсяТаблицаЦеликом(1000, 4)
   
        For I = 1 To 100
            For J = 1 To 10
                [Число1] = I
                [Число2] = J
                [Время] = Time
               
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = [ВсяСтрокаДанных].Value
            Next J
        Next I
       
        'Распечатка всего массива в таблицу.
        Range("G2:J" & (СтрокаТаблицы + 1)) = массВсяТаблицаЦеликом()
    Application.ScreenUpdating = True
   
    MsgBox "Обработка данных завершена, таблица заполнена :)"
End Sub


Теперь массив двумерный, но все равно таблица не распечатывается.
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Hugo121

Сделайте небольшой пример в файле - тогда разговор пойдёт быстрее, народ подключится. Пока всё в тумане - что, куда, зачем...
Toncoin (TON):
UQAUV5ZpXnNQ4JYt9fOI-rtgGw9-ZSFqRqynDzp5cZcoh5GC

Олег*

Цитата: Hugo121 от 30.04.2013, 21:46
Сделайте небольшой пример в файле - тогда разговор пойдёт быстрее, народ подключится. Пока всё в тумане - что, куда, зачем...

В каком тумане?!
Какой еще пример нужен в файле?!
У меня же с самого начала в первом же посте этой ветки файл с примером выложен!
Пока там написано,  что он ни разу не скачан.  А что там не видно, что к посту файл прикреплен? Может форум глючит?
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Hugo121

#5
Упс, я сразу не заметил. Там такой отступ после картинки...

Private Sub CommandButton1_Click()
  Dim I As Long
  Dim J As Long
  Dim СтрокаТаблицы As Long
  Dim массВсяТаблицаЦеликом() As Variant
  Dim a()
 
  Application.ScreenUpdating = False
      ReDim массВсяТаблицаЦеликом(1 To 1500, 1 To 4)
   
        For I = 1 To 100
            For J = 1 To 10
                [Число1] = I
                [Число2] = J
                [Время] = Time
               
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
                a = [ВсяСтрокаДанных].Value
                массВсяТаблицаЦеликом(СтрокаТаблицы, 1) = a(1, 1)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 2) = a(1, 2)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 3) = a(1, 3)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = a(1, 4)
            Next J
        Next I
       
        'Распечатка всего массива в таблицу.
        Range("G2:J" & (СтрокаТаблицы + 1)) = массВсяТаблицаЦеликом()
    Application.ScreenUpdating = True
   
    MsgBox "Обработка данных завершена, таблица заполнена :)"
End Sub


Хотя конкретно в данном случае можно обойтись без диапазонов и массива a() - сразу заполнять данными массВсяТаблицаЦеликом(), а не диапазоны, массив, перекладывать...
Toncoin (TON):
UQAUV5ZpXnNQ4JYt9fOI-rtgGw9-ZSFqRqynDzp5cZcoh5GC

Олег*

Цитата: Hugo121 от 30.04.2013, 22:24
Упс, я сразу не заметил. Там такой отступ после картинки...

Private Sub CommandButton1_Click()
  Dim I As Long
  Dim J As Long
  Dim СтрокаТаблицы As Long
  Dim массВсяТаблицаЦеликом() As Variant
  Dim a()
 
  Application.ScreenUpdating = False
      ReDim массВсяТаблицаЦеликом(1 To 1500, 1 To 4)
   
        For I = 1 To 100
            For J = 1 To 10
                [Число1] = I
                [Число2] = J
                [Время] = Time
               
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
                a = [ВсяСтрокаДанных].Value
                массВсяТаблицаЦеликом(СтрокаТаблицы, 1) = a(1, 1)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 2) = a(1, 2)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 3) = a(1, 3)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = a(1, 4)
            Next J
        Next I
       
        'Распечатка всего массива в таблицу.
        Range("G2:J" & (СтрокаТаблицы + 1)) = массВсяТаблицаЦеликом()
    Application.ScreenUpdating = True
   
    MsgBox "Обработка данных завершена, таблица заполнена :)"
End Sub



Спасибо, так работает.
Единственное, что мне не нравится - это очень много действий вот здесь:


                a = [ВсяСтрокаДанных].Value
                массВсяТаблицаЦеликом(СтрокаТаблицы, 1) = a(1, 1)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 2) = a(1, 2)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 3) = a(1, 3)
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = a(1, 4)



У меня в той программе, куда мне это надо будет вставить, этот кусок кода будет находиться внутри трех (!) вложенных циклов, поэтому он будет прогоняться очень-очень много раз, а это много дополнительного времени. Я, конечно, понимаю, что это все-таки не обращение к ячейкам, а непосредственная обработка в памяти, поэтому все будет происходить гораздо быстрее, чем при обращении к самим ячейкам, но все-таки это сейчас написано в таком виде, что просто напрашивается на дополнительную оптимизацию :)

А все-таки нельзя ли как-нибудь целиком всю строку сразу считывать в массив массВсяТаблицаЦеликом? Ведь я именно для этого специально раположил все необходимые для считывания данные в одну строчку, чтобы (как предполагалось) считывать их именно построчно и сразу вставлять в массив.


Цитата: Hugo121 от 30.04.2013, 22:24
Хотя конкретно в данном случае можно обойтись без диапазонов и массива a() - сразу заполнять данными массВсяТаблицаЦеликом(), а не диапазоны, массив, перекладывать...

Честно говоря, не совсем понял вашу мысль. Объясните, пожалуйста, что вы имеете в виду.
Может быть это как раз и есть то, что мне нужно, то есть последовательное считывание (добавление) всей строки ЦЕЛИКОМ в массив массВсяТаблицаЦеликом?
Муж это единственный зарегенный юзер, а все остальные это хакеры :)

Hugo121

Я имел ввиду так:
        For I = 1 To 100
            For J = 1 To 10
'                [Число1] = I
'                [Число2] = J
'                [Время] = Time
'
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
'                a = [ВсяСтрокаДанных].Value
                массВсяТаблицаЦеликом(СтрокаТаблицы, 1) = Time
                массВсяТаблицаЦеликом(СтрокаТаблицы, 2) = I
                массВсяТаблицаЦеликом(СтрокаТаблицы, 3) = J
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = I + J
            Next J
        Next I

Целиком переложить сразу всю строку из массива в массив можно как-то с помощью CopyMemory - но я как-то не освоил, не знаю, можно ли в таком направлении перекидывать...
Toncoin (TON):
UQAUV5ZpXnNQ4JYt9fOI-rtgGw9-ZSFqRqynDzp5cZcoh5GC

Олег*

Цитата: Hugo121 от 30.04.2013, 23:39
Я имел ввиду так:
        For I = 1 To 100
            For J = 1 To 10
'                [Число1] = I
'                [Число2] = J
'                [Время] = Time
'
                СтрокаТаблицы = СтрокаТаблицы + 1
               
                'Считываем целиком строку полученых данных в массив.
'                a = [ВсяСтрокаДанных].Value
                массВсяТаблицаЦеликом(СтрокаТаблицы, 1) = Time
                массВсяТаблицаЦеликом(СтрокаТаблицы, 2) = I
                массВсяТаблицаЦеликом(СтрокаТаблицы, 3) = J
                массВсяТаблицаЦеликом(СтрокаТаблицы, 4) = I + J
            Next J
        Next I


А, понял, что вы имели в виду. Нет, так, к сожалению не получится :)
Здесь (в учебном примере) очень легкая формула (I + J), поэтому ее легко можно вставить в самом макросе, а в "боевой" программе исползуются довольно сложные встроенные формулы листа, которые обрабатывают большие базы данных. И кроме того, там не одно такое вычисляемое значение, а гораздо больше.
Хотя, на самом деле, все можно сделать в самом макросе, без использования встроенных функций листов, но такой подход у меня уже в далеком прошлом :)  Сейчас предпочитаю использовать встроенные функции, где это только возможно. Они работают ГОРАЗДО быстрее макросов.


Цитата: Hugo121 от 30.04.2013, 23:39
Целиком переложить сразу всю строку из массива в массив можно как-то с помощью CopyMemory - но я как-то не освоил, не знаю, можно ли в таком направлении перекидывать...

Ну все равно спасибо за подсказку. Попробую покопать в этом направлении.

Хотя, на самом деле, даже тот вариант, который вы предложили, по идее, должен работать значительно быстрее, чем это происходит сейчас. Завтра буду пробовать.
Муж это единственный зарегенный юзер, а все остальные это хакеры :)