Jump to content

Fast Associative Array UDF


Ward
 Share

Recommended Posts

A lot of fashion languages have building associative array support (aslo hashtable, dictionary, or map, etc. ), but AutoIt not. However, there are at least two solutions. One is using Scripting.Dictionary object. It is the fast way and very easy to use, but both keys and values can only be string. Another solution is to store key/value pairs in array, for example Nutster 's AssocArrays UDF. It is workable, but very slow.

 

I tried using another way to implement an associative array: storing the key and value in global variable. And I found it is a reliable and effective way. However, because of lacking "undeclared" method for global variable in AutoIt, so some memory leakage is not avoidable. If you DO VERY CARE ABOUT memory usage, please don't use this UDF (and maybe please don't use AutoIt ;) ). A way to avoid too much memory leakage is to declare an associative array returned by AACreate() as a global or static variable, especially when you create an associative array in a function call and clear it before return.

 

In summary, Advantages:

 

  • Pure AutoIt script
  • Number, string, and bninary can be accept as key
  • Any AutoIt variant can be valuse (except Default)
  • Speed will not disappoint you

And disadvantage:

 

  • Allocated memory can't be released fully after associative array is destroyed

In addition, here are some time trial result tested in my computer (INTEL CORE i5 M520). My UDF:

 

TimeTrial for Put/Get 100 times: 18.6153493770439
TimeTrial for Put/Get 1000 times: 77.7477725445058
TimeTrial for Put/Get 10000 times: 689.465468424892
TimeTrial for Put/Get 100000 times: 7204.9405338194

Scripting.Dictionary:

 

TimeTrial for Put/Get 100 times: 9.30057916931989
TimeTrial for Put/Get 1000 times: 37.4383806694381
TimeTrial for Put/Get 10000 times: 460.47318000863
TimeTrial for Put/Get 100000 times: 7487.94427179176

Nutster 's AssocArrays UDF:

 

TimeTrial for Put/Get 100 times: 40.951115509276
TimeTrial for Put/Get 1000 times: 552.447902344774
TimeTrial for Put/Get 10000 times: 6341.65772517276
TimeTrial for Put/Get 100000 times: 82063.8022810111

 

Functions List:

 

; AACreate()
;   Create an associative array
;
; AAVerify(ByRef $AA)
;   Verify if the given variable is an associative array
;
; AAKeyHash(ByRef $AA, ByRef $Key)
;   Convert a key to a unique string (using internal)
;
; AAPut(ByRef $AA, $Key, $Value)
;   Add a Key/Value pair
;
; AAGet(ByRef $AA, $Key)
;   Get the value of the key
;
; AADelete(ByRef $AA, $Key)
;   Delete the key in an associative array
;
; AAExists(ByRef $AA, $Key)
;   Check if the key exists in an associative array
;
; AAGetCount(ByRef $AA)
;   Get the count of an associative array
;
; AAGetKeys(ByRef $AA)
;   Get an array of keys, by default the first element ($array[0]) contains the count
;
; AAGetValues(ByRef $AA)
;   Get an array of values, by default the first element ($array[0]) contains the count
;
; AAClear(ByRef $AA)
;   Delete all elements in an associative array
;
; AADestroy(ByRef $AA)
;   Destroy an associative array

 

AssociativeArray.zip

 

2011/08/19 Update Note:

 

  • Fix some bug, thank to udgeen.
  • Fix the Int32/Int64 key issue.

AssociativeArray.zip

Edited by Ward

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Link to comment
Share on other sites

A great work! Hashes are very usefull for log parcing tasks. Please fix an errors in udf and test example:

UDF: line 25. Have to be "Global Enum..."

UDF: line 207. Have to be "Local $Keys[1] = [0]"

UDF: line 233. Have to be "Local $Values[1] = [0]"

Example: line 34, 35. I fixed them in such a way:

Local $x = AAGetKeys($AA)

Local $y = AAGetValues($AA)

_ArrayDisplay($x, 'Keys')

_ArrayDisplay($y, 'Values')

Link to comment
Share on other sites

  • 10 months later...

One is using Scripting.Dictionary object. It is the fast way and very easy to use, but both keys and values can only be string.

I don't think this is at all true. I've tested the dictionary object, and I can use strings and integers as keys, and anything as a value:

$d = ObjCreate("Scripting.Dictionary")
$obj = ObjCreate("Scripting.Dictionary")
$d.Add("a", "one")
$d.Add("b", 2)
$d.Add(3, $obj)
$d.Add("3", "strings are diff from integers")
$d.Add(4, Binary("binary"))
$i = $d.Item("a")
ConsoleWrite($i & " : " & VarGetType($i) & @CRLF)
$i = $d.Item("b")
ConsoleWrite($i & " : " & VarGetType($i) & @CRLF)
$i = $d.Item(3)
ConsoleWrite(" : " & VarGetType($i) & @CRLF)
$i = $d.Item("3")
ConsoleWrite($i & " : " & VarGetType($i) & @CRLF)
$i = $d.Item(4)
ConsoleWrite($i & " : " & VarGetType($i) & @CRLF)
Link to comment
Share on other sites

I don't think this is at all true. I've tested the dictionary object, and I can use strings and integers as keys, and anything as a value:

Oh, really? Thank you for point it out.

I remembered I've tested it very long time ago, and only string can be used.

Maybe my information is out of date.

But in fact, I wrote this UDF because I had to write some tool on WinPE and it don't have Scripting.Dictionary object.

Thany you anyway.

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...