objects: enumerator object queries

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

objects: enumerator object queries

28 Jan 2018, 16:06

- Some basic examples to get things started.
- Two types of syntax are used:
[enum.next(k,v)]
For-loop
https://autohotkey.com/docs/commands/For.htm
[enum[k,v]]
Enumerator
https://autohotkey.com/docs/objects/Enumerator.htm

Code: Select all

q:: ;for loop via while
;the Next method returns 1 or 0, and outputs vKey/vValue ByRef

;as separate lines instead of a loop
;oArray := ["a", "b", "c"]
;oEnum := oArray._NewEnum()
;vRet := oEnum.Next(vKey, vValue)
;MsgBox, % "[" vRet "] " vKey " " vValue
;vRet := oEnum.Next(vKey, vValue)
;MsgBox, % "[" vRet "] " vKey " " vValue
;vRet := oEnum.Next(vKey, vValue)
;MsgBox, % "[" vRet "] " vKey " " vValue
;vRet := oEnum.Next(vKey, vValue)
;MsgBox, % "[" vRet "] " vKey " " vValue

;using enum.next(k,v) syntax (see link for an example)
;For-loop
;https://autohotkey.com/docs/commands/For.htm
oArray := ["a", "b", "c"]
oEnum := oArray._NewEnum()
while oEnum.Next(vKey, vValue)
	MsgBox, % vKey " " vValue

;the same loop again but using enum[k,v] syntax (see link for an example)
;Enumerator
;https://autohotkey.com/docs/objects/Enumerator.htm
oEnum := oArray._NewEnum()
while oEnum[vKey, vValue]
	MsgBox, % vKey " " vValue

;the same loop again but using a for loop
for vKey, vValue in oArray
	MsgBox, % vKey " " vValue

;note: returns nothing
oEnum := oArray._NewEnum()
for vKey, vValue in oEnum
	MsgBox, % vKey " " vValue

;note: returns nothing
for vKey, vValue in oArray._NewEnum()
	MsgBox, % vKey " " vValue
return

w:: ;in this example, we see what happens if we keep applying Next, even after it has returned a 0
oArray := ["a", "b", "c"]
oEnum := oArray._NewEnum()
Loop, 6
{
	vRet := oEnum.Next(vKey, vValue)
	MsgBox, % "[" vRet "] " vKey " " vValue
}
return

e:: ;in this example we repeatedly restart the loop
oArray := ["a", "b", "c", "d", "e", "f"]
oEnum := oArray._NewEnum()
Loop, 10
{
	if (Mod(A_Index, 3) = 1)
		oEnum := oArray._NewEnum()
	oEnum.Next(vKey, vValue)
	MsgBox, % vKey " " vValue
}
return

r:: ;this produces two separate enumerators, so the loops don't interfere with each other and can occur separately
vOutput := ""
oArray := StrSplit("abc")
for vKey, vValue in oArray
{
	vOutput .= "1 " vKey " " vValue "`r`n"
	for vKey, vValue in oArray
		vOutput .= "`t" "2 " vKey " " vValue "`r`n"
}
MsgBox, % vOutput
return

t:: ;what happens if we delete a key partway through using RemoveAt/Delete
vOutput := ""
oArray := StrSplit("abc")
for vKey, vValue in oArray
{
	if (oArray.2 = "b")
		oArray.RemoveAt(2)
	vOutput .= "1 " vKey " " vValue "`r`n"
	for vKey, vValue in oArray
		vOutput .= "`t" "2 " vKey " " vValue "`r`n"
}
MsgBox, % vOutput

vOutput := ""
oArray := StrSplit("abc")
for vKey, vValue in oArray
{
	if (oArray.2 = "b")
		oArray.Delete(2)
	vOutput .= "1 " vKey " " vValue "`r`n"
	for vKey, vValue in oArray
		vOutput .= "`t" "2 " vKey " " vValue "`r`n"
}
MsgBox, % vOutput
return
- A query, what information can we reveal about enum objects?
- Do they typically contains keys, methods, properties, what?

Code: Select all

q:: ;what information can we reveal about enum objects
;these attempts reveal nothing

oArray := ["a", "b", "c"]
oEnum := oArray._NewEnum()
vOutput := ""
for vKey, vValue in oEnum
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput

oEnum := oArray._NewEnum()
vOutput := ""
for vKey, vValue in oEnum.base
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return
Links (documentation webpages containing '_NewEnum' in the text):
For-loop
https://autohotkey.com/docs/commands/For.htm
Enumerator
https://autohotkey.com/docs/objects/Enumerator.htm
Object
https://autohotkey.com/docs/objects/Object.htm
ComObjArray()
https://autohotkey.com/docs/commands/ComObjArray.htm
ComObjGet()
https://autohotkey.com/docs/commands/ComObjGet.htm
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

04 Feb 2018, 11:43

- I've looked through information about enumerators, and I haven't had too many problems. So it looks like my class object research journey is coming to an end. And so then I can write my object class tutorial.
- I will post some useful enumerator links, and a few minor queries in the next post.
- I have one basic query here, why don't the 'doesn't work' lines work?

Code: Select all

q:: ;inform when _NewEnum is invoked
oArray := new MyInformNewEnumClass
MsgBox
oArray.Push("a", "b", "c")
vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return

class MyInformNewEnumClass
{
	_NewEnum()
	{
		MsgBox, % A_ThisFunc
		;return this ;doesn't work
		;return ["a","b","c"] ;doesn't work
		return ObjNewEnum(this)
	}
}
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
A_AhkUser
Posts: 1147
Joined: 06 Mar 2017, 16:18
Location: France
Contact:

Re: objects: enumerator object queries

04 Feb 2018, 12:37

Hi jeeswg,
jeeswg wrote:- I have one basic query here, why don't the 'doesn't work' lines work?
._NewEnum() retrurns an enumerator object; ["a","b","c"] is an array, while ["a", "b", "c"]._NewEnum() or ObjNewEnum(this) is actually an enumerator object; this is also the reason why this doesn't work with this.
Maybe you can try somthing like the following:

Code: Select all

#NoEnv
#SingleInstance force
SetWorkingDir % A_ScriptDir
SendMode, Input
CoordMode, ToolTip, Screen
#Warn
; Windows 8.1 64 bit - Autohotkey v1.1.27.04 32-bit Unicode

q:: ;inform when _NewEnum is invoked
oArray := new MyInformNewEnumClass("a", "b", "c")
oArray.push("z")
vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return


Class MyInformNewEnumClass {

	__New(__collection*) {
	this.collection := [__collection*]
	}
   	__Call(__callee, __params*) {
        if (__callee = "_NewEnum") {
			; return this.collection._NewEnum()
			return ObjNewEnum(this.collection)
        } else if (__callee = "push") {
			this.collection.push(__params*)
		}
    }

}
my scripts
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

04 Feb 2018, 13:04

Collected threads that contain both '_NewEnum(' and 'Next(':

[GeekDude tutorial]
How to create custom enumerator objects - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=7&t=7199

[Coco examples][the first two use a nested class]
associative array count? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=518
How to make keys in objects case-sensitive? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=3786
find previous key in associated array - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=5489
Insert obj to another obj without loop? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=6813

[method syntax (newer) v. function syntax (older)]
Objects
https://autohotkey.com/docs/Objects.htm#Meta_Functions

[lexikos examples]
[note: OrderedArray() uses the old-school function syntax, not the method syntax]
OrderedArray() Invalid - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=2759
ObjCount() or ObjLength() or ObjLen() - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=3950
with Expression [ as Target ] { BLOCK } - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=9659
Parentheses when calling gets? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=10482
Getting to first/next key in custom enum/next() - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=23967

[further examples: gabrieldane/jethrow/Neuromancer]
For loop question - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/6691 ... ntry423515
enum type and while loop - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/7886 ... hile-loop/
Sort contents of objects in original input order - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=8663
No-SMTP email sending. Send email from server with PHP (when local access to SMTP is blocked or not available) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=18182

[recent threads featuring Helgef/HotKeyIt/jeeswg]
case sensitive/case insensitive arrays (maintain key order, no key autosort) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=29198
objects: ordered array (function syntax to method syntax) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=31472
objects: get correct case key name - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=31641
objects: 0-based array, shift key numbers by an offset - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=34610
Ordered Associative Array - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=37083
How to add to the key of a For-loop - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=38172
For Each Nested Class - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=38399
traditional for loop: for i = a to b (step c) possibilities - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=43022
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

04 Feb 2018, 14:48

- Thanks A_AhkUser. One thing I'd like to do is to create a class that works exactly as the standard AutoHotkey array does, but that shows a MsgBox every time __XXX/_NewEnum/Next methods are invoked. I'm wondering if this can be done for _NewEnum/Next without using any temporary keys.
- Also, the standard enumerator objects that standard AutoHotkey arrays use, seem to be essentially normal arrays, but subtly different, I'm wondering what exactly they consist of.
- I thought that possibly a standard array could be used as an enumerator object, and use the standard Next method, but this doesn't seem to be the case.

- A query. What's going on here? A class extending its own nested class?
Parentheses when calling gets? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 116#p58116
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: objects: enumerator object queries

06 Feb 2018, 04:30

- Also, the standard enumerator objects that standard AutoHotkey arrays use, seem to be essentially normal arrays, but subtly different, I'm wondering what exactly they consist of.
What are the similarities? Almost none I'd say. The built-in enumerator object only has one method, that is next. You cannot do any thing else with it than call next. Before you ask, enum[k,v] is the same as enum.next(k,v). In short, the enumerator object consists of a reference to the object being enumerated, an index and a next method. In script code, it would look something like this,

Code: Select all

; v2
class enum {
	i := 1
	__new(o){
		objrawset(this,"o",o)
	}
	next(byref k:="", byref v:=""){
		if this.i > this.o.maxindex()	; only integer keys in this example. 
			return false
		v := this.o[k:=this.i++]
		return true
	}
	__set(p*){
		throw exception("Unknown property or method.",-1)
	}
	__call(m,p*){
		if m != "next"
			throw exception("Unknown property or method.",-1)
	}
	__get(byref k:="", byref v:=""){
		return this.next(k, v)	
	}
}
; example
a := [4,1]
e := new enum(a)

while e[k,v]
	msgbox k "`t"  v
- I thought that possibly a standard array could be used as an enumerator object, and use the standard Next method, but this doesn't seem to be the case.
Arrays do not have a next method.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

06 Feb 2018, 09:55

- Thanks. I usually see custom enumerators make use of linear arrays. If you wanted to use a custom enumerator on an associative array, it seems that you would have to use a standard enumerator at some point to retrieve those keys in order. Either, before you pass the object to the custom enumerator, or while it's enumerating. So you end up enumerating everything twice, and possibly with an enumerator within an enumerator.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: objects: enumerator object queries

06 Feb 2018, 12:49

You have to use the standard enumerator to retreive key/values in any order of an associative array, you cannot access by key-index (undocumented way), like the built-in enumerator does.

My example only works for dense linear arrays.

Cheers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

28 Jul 2018, 12:00

- It seems that I never did a simple custom enumerator class example, so here's a simple custom enumerator class example to loop through an object in reverse order:

Code: Select all

class MyEnumReverseClass
{
	__New(obj)
	{
		this.data := obj
		this.temp := []
		for k in obj
			this.temp.Push(k)
		this.count := this.temp.Length()
		this.index := this.count
	}
	Next(ByRef k:="", ByRef v:="")
	{
		if !this.index
			return 0
		k := this.temp[this.index]
		v := this.data[k]
		this.index--
		return 1
	}
}

q:: ;loop through an object in reverse order
oArray := {key1:"value1", key2:"value2", key3:"value3"}

oEnum := new MyEnumReverseClass(oArray)
vOutput := ""
;while oEnum[vKey, vValue] ;didn't work
while oEnum.Next(vKey, vValue)
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return

w:: ;delete odd letters - loop through an object in reverse order, and delete keys
oArray := StrSplit("abcdefghijklmnopqrstuvwxyz")

oEnum := new MyEnumReverseClass(oArray)
while oEnum.Next(vKey)
	if !(A_Index & 1) ;if even
		oArray.Delete(vKey)

vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return
- Note: It seems that you can't specify a custom enumerator to use with a for loop, or with the enumobj[k, v] notation. Both notations will use the enumerator specified by _NewEnum().
- However, it seems that you can use a custom enumerator with the enumobj.Next(k, v) notation.
- In short, the enumobj.Next(k, v) notation makes it possible to use any enumerator with any array, whereas the other notations limit you to using whatever enumerator is specified by the _NewEnum() method associated with the object's class.
- Relevant link:
Enumerator Object - Definition & Usage | AutoHotkey
https://autohotkey.com/docs/objects/Enumerator.htm

- Here's another example which allows you to loop through an object in the standard order *and* delete keys without any surprising results. Note: this class is designed for use with the *Delete* method, not with the RemoveAt method. (Delete removes a specific key and does not alter any other keys, whereas RemoveAt removes a key and shuffles the indexes for any integer keys.)

Code: Select all

class MyEnumDeleteHelperClass
{
	__New(obj)
	{
		this.data := obj
		this.temp := []
		for k in obj
			this.temp.Push(k)
		this.count := this.temp.Length()
		this.index := 1
	}
	Next(ByRef k:="", ByRef v:="")
	{
		if (this.index > this.count)
			return 0
		k := this.temp[this.index]
		v := this.data[k]
		this.index++
		return 1
	}
}

;note: surprising results with a standard enumerator
q:: ;delete odd letters - loop through an object, and delete keys
oArray := StrSplit("abcdefghijklmnopqrstuvwxyz")

vOutput := ""
for vKey, vValue in oArray
	if (A_Index & 1) ;if odd
		oArray.Delete(vKey)

vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return

;note: more desirable results with a custom enumerator
w:: ;delete odd letters - loop through an object, and delete keys
oArray := StrSplit("abcdefghijklmnopqrstuvwxyz")

oEnum := new MyEnumDeleteHelperClass(oArray)
while oEnum.Next(vKey)
	if (A_Index & 1) ;if odd
		oArray.Delete(vKey)

vOutput := ""
for vKey, vValue in oArray
	vOutput .= vKey " " vValue "`r`n"
MsgBox, % vOutput
return
Last edited by jeeswg on 28 Jul 2018, 12:24, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: objects: enumerator object queries

28 Jul 2018, 12:17

jeeswg wrote:- Note: It seems that you can't use a custom enumerator with a for loop
For loops expect an object that has a method to return the enumerator, like how I show in this example from my tutorial that you linked further up in this thread. You don't pass the enumerator to the for loop directly.

Code: Select all

for a, b in new Fibonacci()
	MsgBox, % a ", " b ", " b/a ; b/a is an approximation of the golden ratio

class Fibonacci
{
	_NewEnum()
	{
		return new this.MyEnum()
	}
	
	class MyEnum
	{
		Fib := [0, 1]
		Next(ByRef a, ByRef b)
		{
			this.Fib.Push(this.Fib[1] + this.Fib[2])
			a := this.Fib.RemoveAt(1)
			b := this.Fib[1]
			return True
		}
	}
}
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: objects: enumerator object queries

28 Jul 2018, 12:22

It seems that you can't use a custom enumerator with a for loop, or with the enumobj[k, v] notation
Find _newenum and __get in the docs :crazy: .
Edit:
GeekDude wrote:For loops expect an object that has a method to return the enumerator, like how I show in this example from my tutorial that you linked further up in this thread.
And there is a __get example a few posts above it seems
:wtf:
Last edited by Helgef on 28 Jul 2018, 12:28, edited 1 time in total.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

28 Jul 2018, 12:26

- Thanks GeekDude and Helgef, I'd initially worded the text differently (that you couldn't *pass* a custom enumerator to a for loop), but forgot to add some additional information (saying that you could use a custom enumerator if you altered the object's class's _NewEnum method), and then tried to simplify the language (losing any nuance). Hopefully the description is better now.
- @GeekDude: That example of storing the enum object within the class is nice, thanks. You reposted in the right neighbourhood.
- @Helgef: What are you trying to say about __Get? I was trying to keep my class as simple as possible and so avoided using it.
- Btw you stated that 'enum[k,v] is the same as enum.next(k,v)', but is this perhaps not the case, or did I miss something. See ';while oEnum[vKey, vValue] ;didn't work'.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: objects: enumerator object queries

29 Jul 2018, 03:23

- Btw you stated that 'enum[k,v] is the same as enum.next(k,v)', but is this perhaps not the case, or did I miss something
We were talking about the built-in enumerator, I have no idea why you would believe obj[k,v] would be the same as obj.next(k,v) for all obj.
See ';while oEnum[vKey, vValue] ;didn't work'.
It works exactly as expected, if you want custom behaviour when getting you implement __get.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: objects: enumerator object queries

29 Jul 2018, 08:07

Hello Helgef, this code makes it look like you could specify any custom enumerator.

Code: Select all

;Enumerator Object - Definition & Usage | AutoHotkey
;https://autohotkey.com/docs/objects/Enumerator.htm

obj := Object("red", 0xFF0000, "blue", 0x0000FF, "green", 0x00FF00)

; Enumerate!
enum := obj._NewEnum()
While enum[k, v]
    t .= k "=" v "`n"
MsgBox % t
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Chunjee, Google [Bot], JoeWinograd, yabab33299 and 168 guests