Что нового

[Массивы] Autoit + Lua = Ассоциативный масив

tecae

Новичок
Сообщения
5
Репутация
0
AutoIt: 3.3.14.2
Версия: 1.0

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

Простой двумерный массив сразу отпадает... Уж очень длинный поиск.

После поисков в сети нашёл несколько вариантов.
1. тут про Аналог ассоциативного массива Используется объект Scripting.Dictionary.
2. тут [статья на которую "Извините, вам запрещено оставлять внешние ссылки." :ok:] про Associative Array functionality

В проект было внедрен 2-й вариант и все казалось бы нормально но при длительной работе было выявлено неприятную ошибку не нахождение ранее записанного ключа хотя ключ есть.
Проблему временно решил увеличив начальный размер создаваемого массива примерно в 5 раз, то есть объем оперируемыми данными увеличился в 5 раз.
Но проблема осталась... Хотя и достаточно редко ...

Занимаясь настройкой Scite появилась идея использовать механизм Lua по работе с таблицами.

Используя [статью на которую "Извините, вам запрещено оставлять внешние ссылки." :ok: можно найти по тексту "Embedding Lua scripts in AutoIt"] описал dllcall для lua написал библиотеку массива.
Обе библиотеки тестовые еще не отлажены.

Как говорится пока не попробуешь не будешь знать ... Но что скажите на сколько такое решение является конструктивным?

It's Alive Заработало!!!! И намного быстрее чем ожидалось.

Заранее прошу прощения за ляпы в комментариях и синтаксические ошибки :whistle:

Категория: Разное

Описание: Организация взаимодействия Lua и Autoit для реализации ассоциативного массива

Код/Пример:
Код:
#include "luau._au3"
#include "lua_AssocArrays._au3"

Local $USE_Lua_INTRFC = True
Local $dmsg = _display


($USE_Lua_INTRFC = False And Not _lua_init()) ? $USE_Lua_INTRFC = False : $USE_Lua_INTRFC = True
If $USE_Lua_INTRFC = True Then
;~ =---------------------=--------------------=---------------------=---------->>>>>>>>>> test LUA
	;	Использование Lua интерфейса Активация
	$dmsg("+ _lua_init() = OK")
	Local $local_state = 0
	_lua_open_state() ; создаем глобальное состояние
	$local_state = _lua_open_state($LUA_LOCAL_STATE) ; создаем локальное состояние

	_lua_open_libs()
	_lua_open_libs($local_state)

	ConsoleWrite("---- [" & _lua_open_script(@ScriptDir & "\comon.lua") & @CRLF)
	;----- _lua_push
	Local $_aArray[2] = [1, 'Элемент']
	; можно организовать обход масива с записю значение но это накладно на стек 
	; Возможное решение создавать таблицу
	_lua_push($_aArray)

	Local $_bBinary = Binary('0x00204060')
	_lua_push($_bBinary)

	Local $_fBoolean = False
	_lua_push($_fBoolean)

	Local $_hWnd = WinGetHandle('[CLASS:Shell_TrayWnd]')
	_lua_push($_hWnd)
	Local $_hPointer = Ptr(-1)
	_lua_push($_hPointer)

	Local $_iInt = 1
	_lua_push($_iInt) 
	_lua_push(2, $P_COPI) 
	_lua_push(100, $P_SELF_LUA_STATE)
	_lua_push(100, $P_SELF_LUA_STATE, $local_state) 

	Local $_nFloat = 2.0
	_lua_push($_nFloat)

	Local $_sString = 'Некоторый текст'

	_lua_push($_sString)

	Local $_vKeyword_bed = Default
	_lua_push($_vKeyword_bed)

	Local $_vKeyword_ok = Null
	_lua_push($_vKeyword_ok)

	Local $_tStruct = DllStructCreate('wchar[256]')
	_lua_push($_tStruct)

	Local $_oObject = ObjCreate("Scripting.Dictionary")
	_lua_push($_oObject)

	Local $_user_f = _test_f
	_lua_push($_user_f)
	_lua_push($_user_f, Default, $local_state)

	Local $_std_f = MsgBox
	_lua_push($_std_f)
	;-----
	_lua_get_fild("number")
	_lua_get_fild("strings")

	For $x = 1 To _lua_lenght() +1 ; +1 что бы видить невалидный индекс
		ConsoleWrite("index =" & $x & " val =" & _lua_stek_get_value($x) & @CRLF)
		ConsoleWrite("-Tipe name  = " & _lua_get_tipe($x, 1) & @CRLF)
		ConsoleWrite("-Tipe index = " & _lua_get_tipe($x) & " Lenght " & _lua_lenght($x) & @CRLF)

	Next
	;-----
	_lua_pop(1)
	_lua_pop()
	_lua_pop(1, $local_state)
	ConsoleWrite("--- ------------------------_lua_load_func_from_string test --------------------" & @CRLF)
	Local $str_function = "return 10"
	_lua_load_func_from_string($str_function)
	_lua_call(0, 1)
	ConsoleWrite("_lua_load_func_from_string - val =" & _lua_stek_get_value(_lua_lenght()) & @CRLF)
	ConsoleWrite("----------------------------_lua_table_create--------------------------------------" & @CRLF)
	_lua_table_create()
	Local $t = _lua_lenght()
	ConsoleWrite("-Tipe name  = " & _lua_get_tipe(-1, 1) & @CRLF)
	_lua_push("key")
	_lua_push("is value is in table")
	_lua_table_set_fild(-3)
	_lua_push("key1")
	_lua_push("is value is in table1")
	_lua_table_set_fild(-3)
	_lua_push("key2")
	_lua_push("is value is in table2")
	_lua_table_set_fild(-3)
	_lua_push("key3")
	_lua_push("is value is in table3")
	_lua_table_set_fild(-3)
	_lua_push("key4")
	_lua_push("is value is in table4")
	_lua_table_set_fild(-3)



	_lua_push("key")
	_lua_table_get_fild(-2)
	ConsoleWrite("-value from table  =[  " & _lua_stek_get_value(-1) & " ]" & @CRLF)
	ConsoleWrite("----------------------------_lua_table_next--------------------------------------" & @CRLF)
	Local $val = Null
	_lua_push($val)
	While _lua_table_next($t)
		ConsoleWrite("<--- [" & _lua_stek_get_value(-2) & "] = " & _lua_stek_get_value(-1) & @CRLF)
		_lua_pop()
	WEnd
	_lua_pop(_lua_lenght() - 2)
	$t = _lua_lenght()
	ConsoleWrite("before-" & $t & @CRLF)
	_lua_get_fild("AssocArrayT")

	$t = _lua_lenght()

	_lua_push("key4")
	_lua_push("is value is in table4")
	_lua_table_set_fild(-3)

	ConsoleWrite("after-" & $t & @CRLF)
	If _lua_table_is($t) Then
		ConsoleWrite("after- IS TABLE")
		_lua_push($val)

		While _lua_table_next($t)
			ConsoleWrite("<--- [" & _lua_stek_get_value(-2) & "] = " & _lua_stek_get_value(-1) & @CRLF)
			_lua_pop()
		WEnd
		_lua_set_fild("AssocArrayT")

		_lua_get_fild("AssocArrayT")
		$t = _lua_lenght()
		_lua_push($val)
		If _lua_table_is($t) Then
			While _lua_table_next($t)
				ConsoleWrite("< fter save [" & _lua_stek_get_value(-2) & "] = " & _lua_stek_get_value(-1) & @CRLF)
				_lua_pop()
			WEnd
		EndIf
	Else
		ConsoleWrite("after- IS NOT TABLE" & @CRLF)
		ConsoleWrite("-Tipe is  = " & _lua_get_tipe($t, 1) & @CRLF)
	EndIf



	ConsoleWrite("----------------------------_lua_stak_equa--------------------------------------" & @CRLF)

	_lua_push(1)
	_lua_push(2)

	ConsoleWrite("-_lua_stak_equa  = " & _lua_stak_equa() & @CRLF)
	_lua_push(2)
	_lua_push(2)

	ConsoleWrite("-_lua_stak_equa  = " & _lua_stak_equa() & @CRLF)
	ConsoleWrite("----------------------------AssocArray--------------------------------------" & @CRLF)
	Local $assocAr = 0
	Local $DontArr = 0
	_LUA_AssocArrayCreate($assocAr)
	ConsoleWrite("+                   Assoc arr create! index = " & $assocAr & @CRLF)

	_LUA_AssocArrayVerify($assocAr)
	ConsoleWrite("+                  is arr   = " & $assocAr & @CRLF)
	_LUA_AssocArrayVerify($DontArr)
	ConsoleWrite("+                 not arr   = " & $DontArr & @CRLF)

	_LUA_AssocArrayAssign($assocAr, 100, "025")
	ConsoleWrite("+                 apdate/create keyware   = " & $assocAr & @CRLF)

	_LUA_AssocArrayAssign($assocAr, 15, "025")
	ConsoleWrite("+                 apdate/create keyware   = " & $assocAr & @CRLF)

	_LUA_AssocArrayAssign($assocAr, 15, "166668552")
	ConsoleWrite("+                 apdate/create keyware   = " & $assocAr & @CRLF)

	_LUA_AssocArrayAssign($assocAr, 14, "025")
	ConsoleWrite("+                 apdate/create keyware   = " & $assocAr & @CRLF)

	ConsoleWrite("+                 is key   = " & _LUA_AssocArrayExists($assocAr, 100) & @CRLF)
	ConsoleWrite("+                 is not key   = " & _LUA_AssocArrayExists($assocAr, 22) & @CRLF)


	_LUA_AssocArrayDelete($assocAr, 100)

	Local $tempArr = _LUA_AssocArrayKeys($assocAr)
	For $i=0 to UBound($tempArr)-1
		ConsoleWrite("+   " & $tempArr[$i]& @CRLF)
	Next

	ConsoleWrite("------------------------------------------------------------------" & @CRLF)
	_lua_close_state() ; закрывает глобальное состояние
	_lua_close_state($local_state); закрывает локальное состояние

	If _lua_del_init() Then
		$dmsg("+ _lua_del_init() = OK")
	Else
		$dmsg("! _lua_del_init() = ERROR")
	EndIf

Else
	$dmsg("! _lua_init() = ERROR ; окружение Lua не доступно !!!!")
EndIf

Func _test_f($lua_State)
	Local $result = False

	Return $result
EndFunc   ;==>_test_f


Func _display($s_param="")
	ConsoleWrite($s_param & @CRLF)
EndFunc ;===> _display

Файл: Архив
 

Pahuchiy

Новичок
Сообщения
37
Репутация
0
перехожу с луа на autoit и без асс. массивов тяжело. Никак не могу разобраться как использовать приведёный код. Плиз, напишите ПРОСТОЙ пример использования.
 

Prog

Осваивающий
Сообщения
337
Репутация
31
Ассоциативный массив
Код:
$Map_NoElementCheck = 0
$Map_ElementCheck = 1

$dll=DllOpen("MapDLL.dll")

$Map=DllCall($dll, "PTR", "Lib_NewMap")
$Map=$Map[0]
ConsoleWrite("$Map = " & $Map & @CRLF)

for $i=1 to 100
   $Key = "Key_" & $i
   $Ret = DllCall($dll, "int", "Lib_AddMapElement", "PTR", $Map, "WSTR", $Key, "Int", $Map_ElementCheck)
   if $Ret[0]<>0 Then
	  DllCall($dll, "int", "SetData_Integer", "PTR", $Map, "WSTR", "", "Int", $i)
   endif
next


$Ret = DllCall($dll, "Int", "GetData_Integer", "PTR", $Map, "WSTR", "Key_2")
ConsoleWrite("Key_2 = " & $Ret[0] & @CRLF)

$Ret = DllCall($dll, "int", "Lib_MapSize", "PTR", $Map)
$Count = $Ret[0]
ConsoleWrite("Count element = " & $Count & @CRLF)

DllCall($dll, "int", "Lib_ResetMap", "PTR", $Map)


for $i=1 to $Count

   $Ret = DllCall($dll, "int", "Lib_NextMapElement", "PTR", $Map)
   if $Ret[0]<>0 Then
	  $Ret = DllCall($dll, "Int", "GetData_Integer", "PTR", $Map, "WSTR", "")
	  ConsoleWrite($Ret[0] & @CRLF)
   endif
next
Описание функций http://www.purebasic.com/documentation/map/index.html
 

Вложения

A

Alofa

Гость
Pahuchiy сказал(а):
... Никак не могу разобраться как использовать приведёный код.
И не надо вдаваться в это... Это не код - это свалка для личного пользования автора.

OffTopic:
Prog сказал(а):
Ассоциативный массив ...
Для сравнения:
Код:
Local $sText, $Map_NoElementCheck = 1, $Map_ElementCheck = 1
Local $hTimer = TimerInit()

$dll=DllOpen(".\MapDLL\MapDLL.dll")

$Map=DllCall($dll, "PTR", "Lib_NewMap")
$Map=$Map[0]
ConsoleWrite("$Map = " & $Map & @CRLF)

for $i=1 to 20000
   $Key = "Key_" & $i
   $Ret = DllCall($dll, "int", "Lib_AddMapElement", "PTR", $Map, "WSTR", $Key, "Int", $Map_ElementCheck)
   if $Ret[0]<>0 Then
      DllCall($dll, "int", "SetData_Integer", "PTR", $Map, "WSTR", "", "Int", $i)
   endif
next

$Ret = DllCall($dll, "Int", "GetData_Integer", "PTR", $Map, "WSTR", "Key_2")
ConsoleWrite("Key_2 = " & $Ret[0] & @CRLF)

$Ret = DllCall($dll, "int", "Lib_MapSize", "PTR", $Map)
$Count = $Ret[0]
ConsoleWrite("Count element = " & $Count & @CRLF)

DllCall($dll, "int", "Lib_ResetMap", "PTR", $Map)

for $i=1 to $Count
   $Ret = DllCall($dll, "int", "Lib_NextMapElement", "PTR", $Map)
   if $Ret[0]<>0 Then
	  $Ret = DllCall($dll, "Int", "GetData_Integer", "PTR", $Map, "WSTR", "")
	  $sText &= $Ret[0] & @CRLF
   endif
next

$sText &= '+> TimerDiff = ' & Round(TimerDiff($hTimer)/1000, 4) & @CRLF
ConsoleWrite($sText & @CRLF)
DllClose($dll)
Код:
Local $sText, $iUb, $aArray[0], $Count = 20000
Local $hTimer = TimerInit()

For $i = 1 To $Count
	$Key = 'Key_' & $i
	Assign($Key, $i)
Next

ConsoleWrite('Key_2 = ' & Eval('Key_2') & @CRLF)
ConsoleWrite('Count element = ' & $Count & @CRLF) ; Вот тут нужно самому быть в курсе

For $i = 1 To $Count
	$Key = 'Key_' & $i
	$sText &= Eval($Key) & @CRLF
Next

$sText &= '+> TimerDiff = ' & Round(TimerDiff($hTimer) / 1000, 4) & @CRLF
ConsoleWrite($sText & @CRLF)
Prog, а оно того стоит - тащить за скриптом .DLL?
 

Prog

Осваивающий
Сообщения
337
Репутация
31
Падение скорости из-за DllCall...
В этом участке кода
Код:
for $i=1 to 20000
   $Key = "Key_" & $i
   $Ret = DllCall($dll, "int", "Lib_AddMapElement", "PTR", $Map, "WSTR", $Key, "Int", $Map_ElementCheck)
   if $Ret[0]<>0 Then
      DllCall($dll, "int", "SetData_Integer", "PTR", $Map, "WSTR", "", "Int", $i)
   endif
next
90% времени тратится на выполнение DllCall и только 10% на работу функции в dll.
 
Автор
tecae

tecae

Новичок
Сообщения
5
Репутация
0
Pahuchiy сказал(а):
перехожу с луа на autoit и без асс. массивов тяжело. Никак не могу разобраться как использовать приведёный код. Плиз, напишите ПРОСТОЙ пример использования.
Код:
;#Region Обязательно СТАРТ    ---------------------------------------------------------------------------------------------<<<<<
#include "luau._au3"			; функции LUA
#include "lua_AssocArrays._au3" ; функции ассоциативного массива

Local $USE_Lua_INTRFC = True ; ДЛЯ ОТЛАДКИ

($USE_Lua_INTRFC = False And Not _lua_init()) ? $USE_Lua_INTRFC = False : $USE_Lua_INTRFC = True
If $USE_Lua_INTRFC = True Then
	;	Использование Lua интерфейса Активация
	ConsoleWrite("+ _lua_init() = OK")
	_lua_open_state() ; создаем глобальное состояние
	_lua_open_libs()  ; открыть библиотеки STD LUA

   ; файл  comon.lua содержит  AssocArray = {} - тут и хранятся все созданые нами масисы

	ConsoleWrite("---- [" & _lua_open_script(@ScriptDir & "\comon.lua") & @CRLF)
;#EndRegion Обязятельно СТАРТ ---------------------------------------------------------------------------------------------<<<<<
;#Region ТУТ ПОЛЬЗУЕМСЯ МАССИВАМИ




	ConsoleWrite("----------------------------AssocArray--------------------------------------" & @CRLF)
	Local $assocAr = 0  ; переменная далее будет масивом

	Local $DontArr = 0  ; переменная не масив для примера

   ; Создать асс. масив
	_LUA_AssocArrayCreate($assocAr)
	ConsoleWrite("+                   Assoc arr create! index = " & $assocAr & @CRLF)


   ; Проверить асс. массив ли в переменной
	_LUA_AssocArrayVerify($assocAr)
	ConsoleWrite("+                  is arr   = " & $assocAr & @CRLF) ; масив
	_LUA_AssocArrayVerify($DontArr)
	ConsoleWrite("+                 not arr   = " & $DontArr & @CRLF) ; не масив для примера



   ; Вставить ключь значение в асс. масив если присутствует перезаписать значение
	_LUA_AssocArrayAssign($assocAr, 100, "025")


	_LUA_AssocArrayAssign($assocAr, 15, "025") ; создать ключ значение


	_LUA_AssocArrayAssign($assocAr, 15, "166668552") ; перезапись


	_LUA_AssocArrayAssign($assocAr, 14, "025")




   ; Проверить есть ли ключ в асс. масиве
	ConsoleWrite("+                 is key   = " & _LUA_AssocArrayExists($assocAr, 100) & @CRLF) ; существующее
	ConsoleWrite("+                 is not key   = " & _LUA_AssocArrayExists($assocAr, 22) & @CRLF) ; несуществующее


   ; удалить по ключу
	_LUA_AssocArrayDelete($assocAr, 100)


   ; вернуть масив ключей
	Local $tempArr = _LUA_AssocArrayKeys($assocAr)
	For $i=1 to UBound($tempArr)-1
		ConsoleWrite("+   Ключ = " & $tempArr[$i]& " --->")
		ConsoleWrite("+   Значение  = " &_LUA_AssocArrayGet($assocAr, $tempArr[$i])& @CRLF) ; получить значение по ключу
	Next

	ConsoleWrite("------------------------------------------------------------------" & @CRLF)




;#EndRegion ТУТ ПОЛЬЗУЕМСЯ МАССИВАМИ
;#Region Обязятельно ПОСЛЕ ЗАВЕРШЕНИЯ    ---------------------------------------------------------------------------------------------<<<<<
	_lua_close_state() ; закрывает глобальное состояние

	If _lua_del_init() Then
		ConsoleWrite("+ _lua_del_init() = OK")
	Else
		ConsoleWrite("! _lua_del_init() = ERROR")
	EndIf

Else
	ConsoleWrite("! _lua_init() = ERROR ; окружение Lua не доступно !!!!")
EndIf
;#EndRegion Обязательно ПОСЛЕ ЗАВЕРШЕНИЯ    ---------------------------------------------------------------------------------------------<<<<<
 

Вложения

Верх