VBA Collection in Basic

Автор eeigor, 15 ноября 2020, 00:32

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

eeigor

Кто подскажет, поддерживает ли Basic что-то вроде VBA Collection?
Что это за объект: com.sun.star.script.NativeObjectWrapper?
Его нет в числе ThisComponent.AvailableServiceNames, но Xray его видит-таки...
http://www.openoffice.org/api/docs/common/ref/com/sun/star/script/NativeObjectWrapper.html

Обратите внимание на то, что в примере строка "Option Compatible" закомментирована. Компилятор понимает...
Или это из области "недокументированного"?.. В примере ниже код работает. Данные извлекаются по ключу, как и требуется. При копировании структуры копируется указатель, как и ожидалось (по аналогии с массивами)...

'Option Compatible  'turns on the VBA-compatible Basic compiler mode at the module level

Sub TestVBACollection()
   Dim obj As New Collection  'com.sun.star.script.NativeObjectWrapper

   obj.Add("Entry 1", "foo")  'key = "foo", Item = "Entry 1"
   obj.Add("Entry 2", "bar")  'key = "bar", Item = "Entry 2"
   Print "Count: "; obj.Count, obj("foo"), obj("bar")  '>> Count: 2  Entry 1  Entry 2
End Sub


В чём главное отличие от массива? Доступ как по индексу, так и по ключу, а не только по индексу (то есть без поиска перебором элементов). Ключ надо знать. В процедуре должна быть обработка ошибки доступа по ложному ключу. Метод "Add" объекта VBA Collection позволяет вставить элемент в заданную позицию:
.Add(item, [key], [before, after])

А как здесь?

UPD: И здесь также.
Sub TestVBACollectio3()
   Dim obj As New Collection  'com.sun.star.script.NativeObjectWrapper

   obj.Add("Entry 1", "foo")  'Item = "Entry 1", key = "foo",
   obj.Add("Entry 2", "bar", 1)  'Item = "Entry 2", key = "bar", before:=1

   For Each v In obj
       s = s & v & Chr$(10)  '>> Entry2  Entry 1
   Next
   MsgBox s, , "Готово"
   Print obj("foo"), obj(2)  '>> Entry1  Entry 1

   obj.remove("foo")
   Print obj.Count  '>> 1
End Sub


Элемент "Entry 2" вставлен перед первым элементов в коллекции (на скриншоте).
Такую коллекцию легко поддерживать в отсортированном виде, вставляя новый элемент в заданную позицию (в лексикографическом порядке).
Далее элемент удаляется из коллекции. См. также описание на скриншоте 2.

Странно, что переменная obj объявлена как Collection, а не Object.
Хотя уже и так ясно, что это именно Collection, и добавлен он для совместимости с VBA.
Будет ли безопасным его использование в Basic?


UPD2: Объяснение нашлось вот здесь
https://libocon.org/assets/libocon2020/Slides/OsLo-2020.libOBasic.pdf
Правда, требуется установка опции Compatible. Может, она где в настройках задана по умолчанию?

Ещё бы что-то вроде Scripting.Dictionary найти (у меня Linux)... Ведь объект NativeObjectWrapper объявлен как any ObjectId.

P.S. За время эксперимента ошибок не возникало.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

Аналогом объекта Scripting.Dictionary является сервис com.sun.star.container.EnumerableMap. Мой тест (ниже) показывает, что сервис обладает вполне приемлемыми скоростными характеристиками. Приятный, но недокументированный (?) бонус - метод createKeyEnumeration нумерует ключи по возрастанию.

Sub testEnumerableMap
Dim serviceEnumerableMap, oEnumerableMap, keyEnum
Dim nmax as Long, i as Long, key as String, t as Long, s as String, v

Nmax=100000
key=String(200, "a")
 
serviceEnumerableMap=com.sun.star.container.EnumerableMap
oEnumerableMap = serviceEnumerableMap.create("string", "any")

t=GetSystemTicks()
For i=1 To nmax
    oEnumerableMap.put key & i, i
Next i   

s="Запись " & nmax & ": " & (GetSystemTicks()-t)
t=GetSystemTicks()

For i=1 To nmax
    v=oEnumerableMap.get(key & i)
Next i   

s=s & chr(10) & "Чтение " & nmax & ": " & (GetSystemTicks()-t)
t=GetSystemTicks()

KeyEnum=oEnumerableMap.createKeyEnumeration(0)
i=0

While KeyEnum.hasMoreElements
   v=KeyEnum.NextElement
   i=i+1
Wend

s=s & chr(10) & "Нумератор " & i & ": " & (GetSystemTicks()-t)
 
Msgbox s
End Sub
Владимир.

eeigor

Спасибо, Владимир. Это пригодится.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community