Страницы: 1
RSS
Можно ли задать 3х-мерный массив (лист, строка, столбец), не используя цикл?, на VBA
 
Вот код, которым задаем массив со всеми ячейками с данными.

Код
Option Base 1

        'определяем последнюю ячейку с данными
        With ActiveSheet.UsedRange: End With
        lLastRow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
        lLastCol = ActiveSheet.UsedRange.Column + ActiveSheet.UsedRange.Columns.Count - 1
         
        'задаем массив исходных данных
        arr = Range(Cells(1, 1), Cells(lLastRow, lLastCol)).Value

Подскажите, плз, есть ли способ, чтобы превратить массив arr в трехмерный вида  arr(номер_листа, строка, столбец)? Я не могу сообразить синтаксис. Как добавить номер листа?

   
Код
For Each sh In Sheets
    sh.Activate
    arr = Range(Cells(1, 1), Cells(lLastRow, lLastCol)).Value    'как добавить номер листа в эту строку?
Next

Понятно, что можно запустить двойной вложенный цикл (for i=1 to lLastRow, for j=1 to lLastCol) по всем ячейкам каждого листа, а есть ли способ проще, используя Range или еще как то?
Изменено: zamboga - 08.12.2016 12:06:39
 
Нет.
Я сам - дурнее всякого примера! ...
 
С таким подходом и один лист в массив часто запихнуть не получается (если там реально работа идёт), куда там ещё всю книгу...
Просто банально не хватит памяти.
 
А как иначе?

У меня за редким исключением в каждой ячейке есть данные. Мне они нужны для обработки. Через Range проще всего засунуть их в массив, несколько пустых ячеек мне не мешают.

Так было до тех пор, пока не попался файл с несколькими вложенными листами. Понятно, что можно цикл запустить, но я полагал, что как-то можно попроще, используя ActiveSheet.Index и Range
Изменено: zamboga - 07.12.2016 18:10:41
 
Можно использовать массив массивов. Т. е. массив листов, содержащий массивы диапазонов ячеек.
Работать с такой структурой будет удобнее, но, замечание от Hugo из поста № 3 все равно актуально!
Чем шире угол зрения, тем он тупее.
 
zamboga, некоторые функции листа работают с трехмерными ссылками. Они перечислены во втором посте этой темы:
http://www.planetaexcel.ru/forum/?PAGE_NAME=read&FID=8&TID=10351
Эти функции можно использовать в VBA:
Код
msgbox evaluate("SUM(Лист1:Лист3!B5:B7)")
 
Цитата
SAS888 написал:
Можно использовать массив массивов
Я читал про них. Сделал вывод, что для меня массив массивов не подойдет, т.к. дальше работа ведется с каждым элементом массива через
Код
For Each el In arr
    ...      'тут много букв
Next
Поэтому сейчас реализовал через цикл. Будет тормозить на очень больших объемах данных — буду оптимизировать код, благо точно есть куда (далее на основе массива создается Словарь, а можно это сделать сразу)

Цитата
SAS888 написал:
замечание от   Hugo  из поста № 3 все равно актуально!
Массив у меня задается так:
   
Код
    ReDim arr(Worksheets.Count, lLastRowMax, lLastColMax)
lLastRowMax и lLastColMax определяю заранее на каждом листе (циклом)
Код
    For Each sh In Sheets
        sh.Activate
    
        'определяем последнюю ячейку с данными
        With ActiveSheet.UsedRange: End With
        lLastRow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
        lLastCol = ActiveSheet.UsedRange.Column + ActiveSheet.UsedRange.Columns.Count - 1
        
        If lLastRowMax < lLastRow Then lLastRowMax = lLastRow
        If lLastColMax < lLastCol Then lLastColMax = lLastCol

    Next
Глобально, скрипт нужен лично мне, у меня 16 Гиг оперативки, так что я как то не парюсь по этому поводу. Пока памяти хватает с избытком=)
Ну или я не понимаю тогда, что конкретно имеется в виду SAS888 и Hugo в 3м посте. Поясните, плз.

Цитата
Казанский написал:
некоторые функции листа работают с трехмерными ссылками. Они перечислены во втором посте этой темы:
http://www.planetaexcel.ru/forum/?PAGE_NAME=read&FID=8&TID=10351
Спасибо, посмотрел. Не мой случай — я работаю с текстовыми данными.
Изменено: zamboga - 08.12.2016 12:09:15
 
Как-то тестил - у меня в массив помещалось только 30 столбцов, правда не помню сколько было строк.
И это не зависит от размера памяти, но говорят на х64 её доступно больше.
В общем если данных бывает много, да и вообще - лучше в массивы брать не всё, а только то что конкретно нужно.
 
У меня как раз x64 офис.

Вообще, я согласен, что лучше сразу забивать только нужными данными.

У меня в большинстве случаев так и будет, т.к. чаще всего я на "вход" скрипту задаю txt файл, в котором одна колонка, в каждой строке которой всего 1-2 слова.
Когда на вход стал подавать xlsx из нескольких листов, встала вышеописанная задача. Я даже бросился код менять, чтобы Словарь сразу забивать (без массива, как сейчас), но понял, что для этого придется половину проекта переписать, изменив саму логику (алгоритм). Решил, что пока тормозов не будет или ошибки не свалятся от больших объемов — этого делать не буду.

В общем, сделал пока так:
Код
    'создаем массив с данными для поиска
    ReDim arr(Worksheets.Count, lLastRowMax, lLastColMax)
    'Забиваем массив данными
    If Worksheets.Count = 1 Then    'если один лист, используем Range
        ReDim arr(lLastRowMax, lLastColMax)
        arr = Range(Cells(ActiveSheet.UsedRange.Row, ActiveSheet.UsedRange.Column), Cells(lLastRow, lLastCol)).Value
    Else                            'если несколько листов, используем цикл
        For Each sh In Sheets
            sh.Activate
            For i = ActiveSheet.UsedRange.Row To lLastRow
                For j = ActiveSheet.UsedRange.Column To lLastCol
                    arr(ActiveSheet.Index, i, j) = Cells(i, j).Value
                Next
            Next
        Next
    End If
Изменено: zamboga - 08.12.2016 12:29:47
Страницы: 1
Наверх