Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Arrays using ws4ahk, & Dictionary\Array Objects


  • Please log in to reply
17 replies to this topic
jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
Has anybody pursued (or would it even be worth while to pursue) the concept of creating VBScript Arrays using the ws4ahk lib? For example:
var = "cheese"

WS_Initialize()
WS_Exec("Dim Array(3)")
code = 
(
Array(0) = "Clean Underwear"
Array(1) = "Vacuum Cleaner"
Array(2) = "New Computer"
Array(3) = %var%
)
WS_Exec(code)
WS_Eval(x, "Array(2)")
WS_Uninitialize()

msgbox % x
return
<!-- m -->https://ahknet.autoh...y.com/~easycom/<!-- m -->

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I'd think it wouldn't be worthwile unless you're also using ws4ahk for other things. Here are two alternatives:

var = "cheese"

COM_Init()
Array := COM_CreateObject("Scripting.Dictionary")
COM_Invoke(Array, "Item", 0, "Clean Underwear")
COM_Invoke(Array, "Item", "one!", "Vacuum Cleaner") ; Not limited to numeric indices.
COM_Invoke(Array, "Item", 2, "New Computer")
COM_Invoke(Array, "Item", 3, var)
x := COM_Invoke(Array, "Item", 2)
COM_Term()

msgbox % x
return
Requires COM Standard Library.
See also Scripting.Dictionary Object as Associative Array.

var = "cheese"

A_Put(Array, _:="Clean Underwear") ; _:= because parameter is ByRef.
A_Put(Array, _:="Vacuum Cleaner")
A_Put(Array, _:="New Computer")
A_Put(Array, var, 4) ; Index is optional if appending. Note one-based (4 vs 3).
x := A_Get(Array, 2)

msgbox % x
return
Requires A_Array.

Edit:
var = "cheese"

VarSetCapacity(Array, 4*4)
NumPut(DllCall("shlwapi\StrDupA", "str", "Clean Underwear"), Array,  0)
NumPut(DllCall("shlwapi\StrDupA", "str", "Vacuum Cleaner"),  Array,  4)
NumPut(DllCall("shlwapi\StrDupA", "str", "New Computer"),    Array,  8)
NumPut(DllCall("shlwapi\StrDupA", "str", var),               Array, 12)
x := DllCall("MulDiv", "int", NumGet(Array, 12), "int", 1, "int", 1, "str")
Loop, 4
    DllCall("LocalFree", "uint", NumGet(Array, A_Index*4-4))

msgbox % "Mmm, " x "."
return
:lol:

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
Thank you for the quick response and examples Lexikos. I have been looking into using the Scripting.Dictionary object, but I want to have multidimensional capabilities.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Since the index is a string, it can be something like x "," y:
COM_Init()
Array := COM_CreateObject("Scripting.Dictionary")
COM_Invoke(Array, "Item", "w", 2)
COM_Invoke(Array, "Item", "h", 2)
COM_Invoke(Array, "Item", "1,1", "aa")
COM_Invoke(Array, "Item", "2,1", "ab")
COM_Invoke(Array, "Item", "1,2", "ba")
COM_Invoke(Array, "Item", "2,2", "bb")
Loop % COM_Invoke(array, "Item", "h")
{
    n := A_Index
    Loop % COM_Invoke(array, "Item", "w")
        MsgBox % COM_Invoke(Array, "Item", A_Index "," n)
}
COM_Term()
return
Incidentally, it's not very different to how AutoHotkey's pseudo-arrays would be used:
Array_w = 2
Array_h = 2
Array_1_1 = aa
Array_2_1 = ab
Array_1_2 = ba
Array_2_2 = bb
Loop % Array_h
{
    n := A_Index
    Loop % Array_w
        MsgBox % Array_%A_Index%_%n%
}


jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
I have been using the AHK pseudo array's, but I want to be able to pass the array to a function. I do, btw, like your concept for a 2-dimensional array using the Scripting.Dictionary object.

As long as I am getting responses :D, I have 2 questions about the Scripting.Dictionary object:
1) How would the speed compare to using an AHK array? Particularly, I am breaking the contents of a spreadsheet down into a 2-dimensional array to format the data. I would assume a AHK array would operate faster, but would the difference be significant for a spreadsheet full of data?

2) I know the Items()/Keys() functions return an array of values/keys. I've tried using these functions:
x := COM_Invoke(Array, "Items")
x := COM_Invoke(Array, "Keys")
This sets x as number (I assume a pointer to the data in memory). Is there anyway to utilize this return value in the AHK script?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

1) How would the speed compare to using an AHK array?

I don't recall the results of my own benchmarks, but others have said that AHK arrays perform better for relatively small arrays. You'd best benchmark the two methods in the context of your own script before deciding. Some basic benchmarking advice:
[*:3hj1aqf3]Ensure SetBatchLines, -1 is in effect to reduce the impact other activity in the system may have on the results, and to speed up the tests.
[*:3hj1aqf3]If the script deals with AutoHotkey variables, ensure #NoEnv is used. Otherwise empty variables will adversely affect the results.
[*:3hj1aqf3]Average the result of many iterations to get an accurate reading, and run the test a few times to make sure results are consistent.
[*:3hj1aqf3]Use a data set typical to your usage, not something arbitrary.

2) I know the Items()/Keys() functions return an array of values/keys.

Those functions each return a SafeArray, which isn't easy to deal with in AutoHotkey. COM_Enumerate() is much easier:
penum := COM_Invoke(Array, "_NewEnum")
While COM_Enumerate(penum, key) = 0
    text .= key "=" COM_Invoke(Array, "Item", key) "`n"
COM_Release(penum)
MsgBox % text

Note: Post modified to change member information per member request. ~ sinkfaze (07/07/2011)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

COM_Enumerate() is much easier:

Array isn't a COM object. You seemed confused with .NET.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Like the code in jethrow's last post, the code in my previous post was not intended to be run standalone, but with other code that sets Array (such as my Scripting.Dictionary example):
Array := COM_CreateObject("Scripting.Dictionary")
I don't see what .NET has to do with anything (in the AutoHotkey context); IIRC .NET arrays used via COM are also represented as SafeArrays.

:roll:

Note: Post modified to change member information per member request. ~ sinkfaze (07/07/2011)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Array := COM_CreateObject("Scripting.Dictionary")

Oh, I see. Sorry, I thought you meant Keys/Items array.

I don't see what .NET has to do with anything (in the AutoHotkey context); IIRC .NET arrays used via COM are also represented as SafeArrays.

I didn't mean it in conjunction with COM. I supposed you translated some .NET code (under the assumption that .NET has a similar class as Scripting.Dictionary, _NewEnum may correspond to GetEnumerator?).

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I searched the AutoHotkey forums for COM_Enumerate, found an example using _NewEnum and based my example on that.

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
Thank you for the Time & Wisdom! :D

To answer my question above, AHK arrays work faster than using the Scripting.Dictionary when breaking an Excel SS down into a 2D Array. For 8 columns & 2000 rows, a AHK array took about 500 ms, and the Scripting.Dictionary took about 2500 ms. (Approx)

  • Guests
  • Last active:
  • Joined: --
How about anybodies ideas on creating JScript Arrays using the "MSScriptControl.ScriptControl" Object. I like this because it "feels" almost like using real Array, and gives built in function options. Here's an example:
Exe(ptr, code)
{	COM_Invoke(ptr, "ExecuteStatement", code)
}

Eval(ptr, code, param = 0)
{	if param = N	; only for sort() function - to sort numbers correctly
	{	stringreplace code, code, (), , A
		code =
		(	
		function sortNumber(a, b)
		{
		return a - b;
		}
		%code%(sortNumber)
		)
		COM_Invoke(ptr, "ExecuteStatement", code)
		return
	}	
	else
		return COM_Invoke(ptr, "Eval", code)
}

COM_Init()
A := COM_CreateObject("MSScriptControl.ScriptControl")
COM_Invoke(A, "Language", "JScript")

Exe(A, "var arr1 = new Array()")
Exe(A, "var arr2 = new Array()")
code =
(
arr1[0] = "This";
arr1[1] = "is";
arr1[2] = "an"
arr1[3] = "Array"
arr2[0] = "10";
arr2[1] = "5";
arr2[2] = "40";
arr2[3] = "25";
arr2[4] = "1000";
arr2[5] = "1";
) 
Exe(A, code)

msgbox % Eval(A, "arr1.push('Additional')")
msgbox % Eval(A, "arr1.join('.')")
msgbox % Eval(A, "arr2.join('.')")
Eval(A, "arr2.sort()", "N")
msgbox % Eval(A, "arr2.join('.')")

COM_Release(A)
COM_Term()
return


  • Guests
  • Last active:
  • Joined: --
:shock: Sorry, wasn't logged in

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
jethrow:
:( Ok, my computer keeps logging me out when I post.

Edit - That's better! :D

Note: Post modified to change member information per member request. ~ sinkfaze (07/07/2011)

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
I suppose it might be useful sometimes.
COM_Init()
arr := COM_ScriptControl("var arr = new Array('This', 'is', 'a', 'test', '!');`r`n arr;", "JScript", 1)
Loop,   % COM_Invoke(arr, "length")
MsgBox, % COM_Invoke(arr, A_Index-1)
COM_Release(arr)
COM_Term()