Page 1 of 1

GroupAdd, GroupDelete, GroupTranspose

Posted: 24 Dec 2018, 04:35
by CyL0N
I needed a way to create groups i could modify on the fly,and i ended up with this...

EDIT1: I had posted a version with a bad GroupDelete() function.
EDIT2: refactored some of the functions for less overhead. Courtesy of a well made point by @swagfag.

Code: Select all

;Uses a combined list & array Groups index,for ease of use & efficiency,respectively.

GroupAdd("mediaPlayers", "ahk_exe vlc.exe", "ahk_exe mpc-hc.exe")
;GroupDelete("mediaPlayers")

;create new group and make it a 'real' group...
GroupAdd("browsers", "ahk_exe chrome.exe", "ahk_exe firefox.exe")GroupTranspose("browsers")
SetTimer, listGroups, 300
;toogle group member
x::IsInGroup("mediaPlayers","vlc.exe") ? GroupDelete("mediaPlayers", "ahk_exe vlc.exe") : GroupAdd("mediaPlayers", "ahk_exe vlc.exe")

;(de)activate a group... of course group members can't be removed from the transposed 'real' group,only from the custom group they were inherited from...
a::GroupActivate % GroupTranspose("browsers")
d::GroupDeactivate % GroupTranspose("browsers")

#If GroupActive("mediaPlayers")
g::MsgBox 0x40040,, MEDIA PLAYER GROUP ACTIVE
#If

#IfWinActive ahk_group browsers	;Custom Group transformed to real group...
g::MsgBox 0x40040,, BROWSER GROUP ACTIVE
#IfWinActive

listGroups:
ToolTip % A_Groups "`n`n" GroupActive("mediaPlayers") "`n" GroupActive("browsers")
Return

;====================================================================================================

GroupAdd(groupName,groupMembers*){
	Global A_Groups,A_GroupsArr
	( !InStr(A_Groups, groupName ",") ? (A_Groups .= A_Groups ? "`n" groupName "," : groupName ",") : "" )	;initialise group if it doesn't exist...
	For i,groupMember in groupMembers
		( !InStr(A_Groups, groupMember) ? (A_Groups := StrReplace(A_Groups, groupName ",", groupName "," groupMember ",")) : )	;append to or create new group...
	A_Groups := RegExReplace(RegExReplace(A_Groups, "(^|\R)\K\s+"), "\R+\R", "`r`n")	;clean up groups to remove any possible blank lines
	,ArrayFromList(A_GroupsArr,A_Groups)	;rebuild group as array for most efficient cycling through groups...
}

GroupDelete(groupName, groupMember:=""){
	Global A_Groups,A_GroupsArr
	For i,group in StrSplit(A_Groups,"`n")
		( groupMember && group && InStr(A_Groups,groupMember) && groupName = StrSplit(group,",")[1] ? (A_Groups:=StrReplace(A_Groups,group,StrReplace(group,groupMember ","))) : !groupMember && groupName = StrSplit(group,",")[1] ? (A_Groups:=StrReplace(A_Groups,group))  )	;remove group member from group & update group in A_Groups
	A_Groups := RegExReplace(RegExReplace(A_Groups, "(^|\R)\K\s+"), "\R+\R", "`r`n")	;clean up groups to remove any possible blank lines
	,ArrayFromList(A_GroupsArr,A_Groups)	;rebuild group as array for most efficient cycling through groups...
}

ArrayFromList(ByRef larray, ByRef list, listDelim := "`n", lineDelim:=","){
	larray := []
	Loop, Parse, list, % listDelim
		larray.Push(StrSplit(A_LoopField,lineDelim))
}

;Function's below are subject to a performance overhead & hence use A_GroupsArr...as they are repeatedly called...
GroupActive(groupName){
	Global A_GroupsArr
	For i,group in A_GroupsArr
		If (group.1 = groupName)
			For iG,groupMember in group
				If (iG > 1 && groupMember && (firstMatchId := WinActive(groupMember)))
					Return group.1 "," firstMatchId
}

GroupTranspose(groupName){	;makes this custom group,a 'real' group,some use cases....
	Global A_GroupsArr
	For i,group in A_GroupsArr
		If (group.1 = groupName)
			For iG,groupMember in group
				If (iG > 1 && groupMember)
					GroupAdd, % group.1, % groupMember
	Return groupName
}

IsInGroup(groupName, groupMember){
	Global A_Groups
	Loop, Parse, A_Groups, `n
		If (StrSplit(A_LoopField,",")[1] = groupName && InStr(A_LoopField,groupMember))
			Return True
}

;====================================================================================================

Re: GroupAdd, GroupDelete, GroupTranspose

Posted: 25 Dec 2018, 10:19
by swagfag
im perplexed as to how there would be less overhead with a plain old list as opposed to implementing it with arrays, considering all the StrSplits(which ironically also happens to do the very thing u sought to avoid, namely, generating arrays) ure doing every time a function is called

Re: GroupAdd, GroupDelete, GroupTranspose

Posted: 25 Dec 2018, 12:38
by CyL0N
swagfag wrote:
25 Dec 2018, 10:19
im perplexed as to how there would be less overhead with a plain old list as opposed to implementing it with arrays, considering all the StrSplits(which ironically also happens to do the very thing u sought to avoid, namely, generating arrays) ure doing every time a function is called

Well, your most certainly right there's prolific use of arrays for someone trying to avoid using them :problem: ... :lolno: ... I've made changes accordingly that will address any possible overhead, though i still find it's easier to manipulate lists than arrays, so i ended up using a concurrent array, that mirrors list ONLY when a group is added or deleted,which i think is a fair compromise that results in no overhead.

Much Appreciate Your Input... Merry Christmas Dude. :xmas: :salute:

Re: GroupAdd, GroupDelete, GroupTranspose

Posted: 27 Dec 2018, 06:09
by Kavima
swagfag wrote:
25 Dec 2018, 10:19
im perplexed as to how there would be less overhead with a plain old list as opposed to implementing it with arrays, considering all the StrSplits(which ironically also happens to do the very thing u sought to avoid, namely, generating arrays) ure doing every time a function is called
Thank you for help! Merry Christmas!

Re: GroupAdd, GroupDelete, GroupTranspose

Posted: 27 Dec 2018, 07:55
by CyL0N
Kavima wrote:
27 Dec 2018, 06:09
swagfag wrote:
25 Dec 2018, 10:19
im perplexed as to how there would be less overhead with a plain old list as opposed to implementing it with arrays, considering all the StrSplits(which ironically also happens to do the very thing u sought to avoid, namely, generating arrays) ure doing every time a function is called
Thank you for help! Merry Christmas!
Welcome to the forums @Kavima, i'm not sure, but if your' asking about what swagfag indicated, then the implication was my previous approach to using lists vs array was self contradicting and thus a bad approach. He was correct so i ended up defaulting to discrete arrays & lists where appropriate.

Though, if your working with simple lists with list elements that don't require further parsing, lists are simply faster, as indicated in the example below.

Code: Select all

;create list & array with identical data...
SetBatchLines, -1
array := []
Loop 1000000
	list .= A_Index "`n", array[A_Index]:=A_Index

;read array & measure time to loop through every array element
QPX(True)
For k,v in array
	i:=""		;do nothing, just allow array to cycle through.
aPerf := QPX()
QPX(True)
Loop, Parse, list, `n
	i:=""		;do nothing, just cycle through loop.
lPerf := QPX()

MsgBox % "Array Loop:	" aPerf "`nList Loop:		" lPerf



QPX( N=0 ) { ; Wrapper for QueryPerformanceCounter()by SKAN | CD: 06/Dec/2009
	Static F,A,Q,P,X ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 10/Dec/2009
	If	( N && !P )
		Return	DllCall("QueryPerformanceFrequency",Int64P,F) + (X:=A:=0) + DllCall("QueryPerformanceCounter",Int64P,P)
	DllCall("QueryPerformanceCounter",Int64P,Q), A:=A+Q-P, P:=Q, X:=X+1
	Return	( N && X=N ) ? (X:=X-1)<<64 : ( N=0 && (R:=A/X/F) ) ? ( R + (A:=P:=X:=0) ) : 1
}

Re: View first unread post

Posted: 30 Dec 2018, 00:58
by CyL0N
WarnerLok wrote:
29 Dec 2018, 23:23
Clicking that link always just takes me to the first post of the thread. Is there any way to fix this?
It works just fine for me, but it might be that a post has too few posts,find a an unread topic with a lot of posts & you'll see what i mean.

Cheers.