Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

1 Декабрь 2020, 09:09 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Доступно и просто о работе в офисных пакетах
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1   Вниз
  Печать  
Автор Тема: [Закрыта] Присвоение данных массива диапазону и назад  (Прочитано 441 раз)
0 Пользователей и 1 Гость смотрят эту тему.
eeigor
Ubuntu 18.04 LTS • LO 7.0.2.2
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 197



« Стартовое сообщение: 15 Ноябрь 2020, 21:30 »

Обнаружил поведение, отличное от VBA при выполнении операций, указанных в теме.
Код:
' Copies an array to and from a range.
Sub CopyArrayToRange2()
Dim oSheet As Object, oRange As Object
Dim vArr(99, 9) As Variant  '2D-array for range A1:J100

REM vArr = Array(Array("A1", "B1"), Array("A2", "B2"))  'array of arrays (jagged)

Dim r&, c&
For r = 0 To UBound(vArr, 1)
For c = 0 To UBound(vArr, 2)
vArr(r, c) = Chr(c + 65) & r + 1
Next c
Next r

' Копируем данные из массива в диапазон листа.
oSheet = ThisComponent.CurrentController.ActiveSheet
oRange = oSheet.getCellRangeByPosition(0, 0, UBound(vArr, 2), UBound(vArr, 1))
oRange.DataArray = vArr  '.SetDataArray(vArr)
' NOTE: Данные присваиваются, несмотря на то что vArr - это 2D-массив

' Изменяем данные. Делаем что-то ещё...
With oRange.getCellRangeByName("A1")
.String = .String & "*"  'changed
End With

' Копируем данные из диапазона обратно в массив.
' NOTE: Как выяснилось, LO, в отличие от Excel, автоматически
' не преобразует объявленную переменную в 2D-массив, соответствующий
' размерности диапазона ячеек, а присваивает ей массив массивов.
ReDim vArr()

' Осуществляем доступ к элементам внутри массива массивов
' с использованием координат элемента (это не 2D-массив, как хотелось бы).
vArr = oRange.DataArray  '.getDataArray()
MsgBox vArr(0)(0)  '>> A1*
End Sub

Комментарий. Метод диапазона setArrayData() требует массив массивов, но принимая 2D-массив, преобразует его к требуемому виду.
Однако метод getArrayData() возвращает обратно именно массив массивов, требующий другого обращения к элементам:
vArr(row)(column) вместо vArr(row, column)
В результате в коде выше с одной переменной работаем по-разному. Это плохо.

Вопрос: Как получить диапазон листа в виде 2D-массива?. Возможно, надо работать с другими свойствами диапазона. Или что я делаю не так?
UPD: А может, это баг? Два "симметричных" метода работают по-разному...

Справочно:
https://vremya-ne-zhdet.ru/vba-excel/diapazon-yacheyek-i-massiv-obmen-znacheniyami/
https://riptutorial.com/vba/example/16563/jagged-arrays--arrays-of-arrays-
« Последнее редактирование: 16 Ноябрь 2020, 14:55 от eeigor » Записан
sokol92
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 229


WWW
« Ответ #1: 15 Ноябрь 2020, 21:41 »

Документация говорит, что в обоих Get/SetDataArray методах задействованы массивы массивов. В VBA таких методов нет.
Теоретически Вы можете использовать свойство Range.Value (c опцией поддержки VBA) для чтения и записи, однако эффективность такого подхода в современных версиях LO ужасна.
« Последнее редактирование: 15 Ноябрь 2020, 21:45 от sokol92 » Записан

Владимир.
eeigor
Ubuntu 18.04 LTS • LO 7.0.2.2
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 197



« Ответ #2: 15 Ноябрь 2020, 21:51 »

Владимир, я, конечно, могу "выполнить задачу", но..
1. "Симметричные" методы - не симметричны.
2. Я привык работать с 2D-массивами, а не с массивами массивов, а тут работать надо именно с ними.
3. Операция переноса данных на лист для их обработки с применением функций диапазона листа вовсе не бесполезна (сортировка, например, работает очень быстро, но надо очень быстро переносить данные, не в цикле же).
4. Диапазон - это таблица (матрица), скорее 2D-массив, чем массив массивов:
    vArr = Array(Array("A1", "B1"), Array("A2", "B2"))  'для ясности вместо значений даны адреса ячеек

И всё-таки, как правильно переносить данные из массива в диапазон листа и обратно. Может, я что-то делаю неправильно?
« Последнее редактирование: 15 Ноябрь 2020, 21:59 от eeigor » Записан
sokol92
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 229


WWW
« Ответ #3: 15 Ноябрь 2020, 22:08 »

1. Методы симметричны - и там, и там массив массивов. То, что Вам удалось (?) "подсунуть" двумерный массив - недокументированная особенность. Цикл обработки аналогичен Excel:
  • выбрали данные диапазона ячеек листа Calc в массив массивов типа Variant (в Excel VBA двумерный массив типа Variant)
  • обработали циклами по строкам и столбцам данные
  • загрузили обратно (если необходимо)
Сами по себе методы чтения/записи значений ячеек работают довольно быстро на "однородных" данных.

2. Я тоже привык, но это не аргумент. Для меня еще непривычно, что пустые ячейки соответствуют пустой строке, а не Empty.

3-4. Зависит от точки зрения.
« Последнее редактирование: 15 Ноябрь 2020, 22:10 от sokol92 » Записан

Владимир.
eeigor
Ubuntu 18.04 LTS • LO 7.0.2.2
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 197



« Ответ #4: 15 Ноябрь 2020, 22:15 »

Ссылка выше (VBA). Цитата:
"Стоит отметить, что для копирования значений из диапазона ячеек в массив можно использовать только обычную переменную или динамический массив универсального типа (Variant). VBA Excel автоматически преобразовывает их в двумерный массив. Если объявить двумерный массив с указанной заранее размерностью, использовать его не получится, будет сгенерирована ошибка с сообщением: Can’t assign to array (Нельзя назначать массив)".

Но в формах VBA с элементами управления я работал также. Например, при присвоении значений списку и комбобоксу, в которых более одного столбца (через 2D-массив).

UPD: Вот как пришлось исправить код, ибо размерность везде равна 1, а вот вложенность разная:
oRange = oSheet.getCellRangeByPosition(0, 0, UBound(vArr(0)), UBound(vArr))

То, что Вам удалось (?) "подсунуть" двумерный массив - недокументированная особенность.
Теперь надо, чтобы и обратно... Улыбка
« Последнее редактирование: 15 Ноябрь 2020, 22:35 от eeigor » Записан
sokol92
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 229


WWW
« Ответ #5: 15 Ноябрь 2020, 22:47 »

MS Office VBA и LO Basic - разные системы программирования. Синтаксис языков похож (но есть и важные отличия, например, в реализации массивов), объектные модели совершенно иные.

Если пытаться копировать коды "один в один" из VBA в Basic, то даже если макросы будут работать, эффективность этой работы (как в случае с Range.Value) под большим вопросом.
Записан

Владимир.
eeigor
Ubuntu 18.04 LTS • LO 7.0.2.2
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 197



« Ответ #6: 16 Ноябрь 2020, 11:42 »

То, что Вам удалось (?) "подсунуть" двумерный массив - недокументированная особенность.
В сети это используется и описано. И разработчик, реализуя эту возможность, исходил из чего-то...
https://www.debugpoint.com/2014/10/range-processing-using-macro-in-libreoffice-calc-part-1/
Дело в том, что у массива массивов внутренние размерности не заданы и позволяют создавать неравномерные зубчатые (jagged) массивы. У двумерного массива размерность всегда одинакова (таблица или матрица, в отличие от разрежённой матрицы).
Массив массивов, к примеру, позволил бы хранить только непустые значения ячеек: (("A1", "B1", "C1"), ("B2"), ("A3", "C3")).
Мы же всегда, применительно к диапазону, оперируем двумерным массивом. Неудачный подход. Вопрос решался бы просто, если, уже умея принимать двумерный массив (setArrayData), Calc умел бы и возвращать его (getArrayData). Конечно, размер массива известен (size = rows * columns), но средствами Basic его преобразовать нельзя, не прибегая к циклам. Значит, менять способ обращения к элементам в рамках одной программы, как я и показал в примере выше.

UPD: А вообще, есть низкоуровневый конвертер описанных массивов, доступный в Basic? Нет, конечно...
« Последнее редактирование: 16 Ноябрь 2020, 12:21 от eeigor » Записан
eeigor
Ubuntu 18.04 LTS • LO 7.0.2.2
Форумчанин
***
Offline Offline

Пол: Мужской
Сообщений: 197



« Ответ #7: 16 Ноябрь 2020, 14:46 »

...если не считать этот  Подмигивающий
Код:
'   Declare an array of arrays

Sub Test
    Create_Array_of_Arrays(9, 2)  'matrix 10x3
End Sub

Sub Create_Array_of_Arrays(i, k)
    Dim aArray(i) As Variant
    For j = 0 To i
        aArray(j) = DimArray(k)
    Next j
REM Xray aArray
End Sub

P.S. Работать с ними можно, вот только объявить (речь о Basic only) через Dim не получится...
sokol92, может, поэтому и работает метод setDataArray в "недокументированном" режиме? Чтобы создав двухмерный массив, пользователь не был вынужден трансформировать его в массив массивов в цикле, чтобы присвоить диапазону. А вот обратно... То-то и не логично! There are Python list, tuple and so on... Тема закрыта.
« Последнее редактирование: 16 Ноябрь 2020, 15:12 от eeigor » Записан
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!