Переписать код VBA под Libreoffice Basic по поиску в массиве

Автор eugenefoxx, 30 сентября 2018, 10:27

0 Пользователи и 1 гость просматривают эту тему.

eugenefoxx

Здравствуйте! Подскажите, как переписать по Libreoffice Basic следующий код -
Как видно, берутся данные с одной страницы по ключевому столбцу и проводиться поиск соответствующих значений по нему на другой странице.

ThisWorkbook.Worksheets("Сводный анализ").Activate
   With ThisWorkbook.Sheets("Сводный анализ")     'используется кодовое имя
       iLastrow = .Cells(Rows.Count, 5).End(xlUp).Row
       a = Range(.[e3], .Range("E" & iLastrow)).Value
   End With
   With ThisWorkbook.Sheets("Лист1")    'используется кодовое имя
       iLastrow = .Cells(Rows.Count, 2).End(xlUp).Row
       b = Range(.[j6], .Range("B" & iLastrow)).Value
   End With
   
   ReDim c(1 To UBound(a), 1 To 7)
   
   With CreateObject("Scripting.Dictionary")
   
   For i = 1 To UBound(b)
           .Item(b(i, 1)) = i
   Next
   
   For i = 1 To UBound(a)
           If .exists(a(i, 1)) Then
               c(i, 1) = b(.Item(a(i, 1)), 5)
               c(i, 3) = b(.Item(a(i, 1)), 6)
               c(i, 4) = b(.Item(a(i, 1)), 8)
               c(i, 5) = b(.Item(a(i, 1)), 4)
           End If
   Next
   End With

  With ThisWorkbook.Sheets("Сводный анализ")    'используется кодовое имя
       .[f3].Resize(UBound(c), 5) = c
       .Activate
   End With

economist

Ну, во-первых, этот (да и другой) код в LO61 должен работать и так (почти).

Попробуйте вставить код с LO 6.1 Calc и выполните пошагово, по F8:

option vbasupport 1

sub test()
ThisWorkbook.Worksheets("Сводный анализ").Activate
    With ThisWorkbook.Sheets("Сводный анализ")     'используется кодовое имя
        iLastrow = .Cells(Rows.Count, 5).End(xlUp).Row
        a = Range(.[e3], .Range("E" & iLastrow)).Value
    End With
    With ThisWorkbook.Sheets("Лист1")    'используется кодовое имя
        iLastrow = .Cells(Rows.Count, 2).End(xlUp).Row
        b = Range(.[j6], .Range("B" & iLastrow)).Value
    End With
   
    ReDim c(1 To UBound(a), 1 To 7)
   
    With CreateObject("Scripting.Dictionary")
   
    For i = 1 To UBound(b)
            .Item(b(i, 1)) = i
    Next
   
    For i = 1 To UBound(a)
            If .exists(a(i, 1)) Then
                c(i, 1) = b(.Item(a(i, 1)), 5)
                c(i, 3) = b(.Item(a(i, 1)), 6)
                c(i, 4) = b(.Item(a(i, 1)), 8)
                c(i, 5) = b(.Item(a(i, 1)), 4)
            End If
    Next
    End With

   With ThisWorkbook.Sheets("Сводный анализ")    'используется кодовое имя
        .[f3].Resize(UBound(c), 5) = c
        .Activate
    End With
end sub

 
Огромные усилия людей по имплементации VBA в LO направлены на то, чтобы программирование электронных таблиц было безграничным и использована огромная кодовая база примеров на VBA, доставшаяся (да чего уж там, пополняющаяся стократно быстрее каждый день) от Microsoft Excel, самого популярного прикладного приложения в мире. Усилия по самостоятельной доработке имеющихся VBA макросов в Calc окупятся сторицей, вы освоите еще один волшебный инструмент. И в связи с этим есть ещё во-вторых и в-третьих:

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

В-третьих, для таких простых задач (поиск значения в строке другой таблице и возврату значения нужного столбца  в эту) - вовсе не нужны макросы, достаточно освоить часто нужную функцию =ВПР(=VLOOKUP) или связку функций =ИНДЕКС(ПОИСКПОЗ...) или INDEX/MATCH. 
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

eugenefoxx

#2
Пробую запустить в текущем варианте, это приводит к BASIC runtime error. '91' Objectiv variable not set или BASIC runtime error. '12'. ThisWorkbook. Эта ошибка проявляется в строке ThisWorkbook.Worksheets("Сводный анализ").Activate.
По поводу формул. Я их также активно использую, но при создании макроса по обработке нескольких файлов с многотысячными строками, формулы занимают много времени. Поэтому решил в таких ситуациях использовать массивы.

economist

#3
eugenefoxx - пробуете запустить где (ОС, версия LO, приложение Calc?)
"Текущий вариант" - это что: ваш, мой код? 

Вот как я пробовал (вложение). Работает в LO 5.4-6.1

Готовые формулы в 99% реальных задач не могут считать медленнее чем макрос.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

eugenefoxx

#4
"Текущий вариант" - это ОС - Archlinux, LO 6.1, Calc
Запускаю код из внешнего файла. В начале прописан код на чистом LO Basic (обработка внешних файлов и загрузка их в основной сводный внешний файл (шаблон)), далее я пытаюсь запустить это самый код на VBA, и возникает ошибка на ThisWorkbook.Worksheets("Сводный анализ").Activate. В Вашем примере у меня также код работает.

economist

Цитата: eugenefoxx от 30 сентября 2018, 18:06В Вашем примере у меня также код работает.

Если мой код в моем файле работает - добавьте в свой "внешний файл" (полагаю это ODS-файл) - первую строку из кода в посте #1 и надо переоткрыть файл. Также стоит проверить в Настройки - Свойства VBA - поставить все галки и переоткрыть файл.

Метод Activate - это из VBA, не исключено что под Арчем что-то из LO выпилено.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

eugenefoxx

#6
Переделал на запуск кода в текущей книге (.ods). Возникла другая проблема. Теперь на строчке .Item(b(i, 1)) = i . Ошибка BASIC runtime error. '323'. Module cannot be loaded; invalid format. Возможно это связано с  With CreateObject("Scripting.Dictionary"). Я думаю это приговор.

economist

#7
Эта строка

With CreateObject("Scripting.Dictionary")

вообще не нужна. Удалите её и закрывающий End with.
Строку с ошибкой легко вычислить отладкой по F8.
Вы бы описали словами что должен делать макрос.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

bigor

Цитата: economist от 30 сентября 2018, 22:31Вы бы описали словами что должен делать макрос.
И файлик приложили
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

eugenefoxx

Почему я сказал, что это приговор, потому что Dictionary Object - Description Object that stores data key, item pairs и у него есть свойство Item. По всей видимости  vbasupport такой объект не поддерживает. И поиск свойства item не будет работать вне цикла объекта Dictionary, т.к. это, как выяснили, его свойство.

bigor

так напишите чего надо сделать, может можно это и без Dictionary Object - Description Object that stores data key, item pairs  сделать
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

mikekaganski

Интересное кино...

Как всем известно, Dictionary Object - это COM-объект, предоставляемый MS Script Runtime, являющегося компонентом Windows. Я полез искать документацию, подтверждающую этот простой факт (чтобы пояснить, что это нормально, когда ОС-специфичные вещи отказываются работать на других платформах). И был удивлён, что во время недавнего преобразования документации на сайте Microsoft статьи по Script Runtime волшебным образом перекочевали в объекты VBA. Конечно, можно найти и архивную копию (которая, внезапно, является более полной)... но вот я теперь думаю: это что, такой тонкий способ расширить определение VBA до "всё на свере, что есть в Windows", чтобы сделать реализацию этого невозможной третьей стороной? (Интересно, а под macOS как это работает в MS Office?)
С уважением,
Михаил Каганский

economist

eugenefoxx - повода для грусти нет. Любой "словарь" можно заменить двумерным массивом N*2. Да и других вариантов масса. Может стоит задуматься и выбрать что-то еще?   

Если я сталкиваюсь с 20k+ строками (а это предел "комфорта" и в Excel. и в Calc), - то сразу иду либо в СУБД (SQLite) или в Python с его сверхбыстрыми list, tuple, dictionary, написанных на языке С, с кучей методов поиска, сортировки, реверсного поиска итп. Также не стоит сбрасывать со счетов старый добрый CSV/TSV-формат, который читается и парсится на LOBasic и VBA почти одинаково быстро и уступает СУБД/Python считанные "разы" в скорости.   
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

eugenefoxx

#13
economist - спасибо за советы. Я это понимаю. Буду пробовать, т.к. не сильно упражняюсь в таких "занятиях". Хотелось на LOBasic, но пока еще решаю эту проблему для себя.
В целом задача простая. Как видно на примере VBA, на одной странице выбирается ключевой столбец с данными, считывается до конца строки, потом по нему в другом массиве, на другой странице, проводиться поиск необходимых значений, соответственно по такому же ключу. Т.е. тут сравниваются две базы данных, которые должны соответствовать другу другу. Не знаю, нужен ли для этого пример файла с данными. Тут можно все что угодно представить. Если будет хоть какое-то решение, буду благодарен. Допилю сам, лишь бы сдвинуться с мертвой точки. Как уже говорил, формулы я применяю, но тут по сути нужен скрипт для автоматической обработки, тем более массив информации большой.

economist

Скрипт/макрос, даже если массив огромен, может быть тут "однострочный", просто вставляющий готовую нужную формулу. Это выглядит примерно так:

[B1:B10000].FormulaLocal="=ВПР(ЧТО;ГДЕ;СТОЛБЕЦ;ЛОЖЬ)"

И будет то, что нужно - браться по ключу данные из другой таблицы и подставляться в имеющуюся.
Именованные диапазоны ЧТО ГДЕ - тоже можно задать макросом, или указать явно, например так [A2:A10000]

Макросы имеют один "побочный эффект" - они часто провоцируют "поток программирования" там, где это вовсе не нужно. Массивы, словари, циклы, сплошные области данных - это всё в данной задаче и VBA-коде - избыточно.

Формулой данная задача (построчное сравнение двух "перемешанных" таблиц) - решается примерно за минуту, именно столько на неё тратят мои коллеги, "не умеющие" макросы, но умеющие =ВПР().   
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...