object get keys/values prototype function

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

object get keys/values prototype function

23 Jan 2018, 20:14

- This is partly a response to:
Object.HasValue/Contains/KeyOf/FindValue - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 37&t=30536

- There are multiple searches/comparisons that are often useful between two arrays, and this prototype JEE_ObjGetVals function, makes much of this possible.
- AutoHotkey already has an ObjHasKey function, but not an ObjHasVal function. If you check whether an object has at least one key with a particular value, you'd want to know the name of the key contains it, and possibly the names of all keys that have such a value.
- Furthermore, you may want to check for one value, or multiple values, or wildcard values. Also, maybe you'd like the same functionality to search the text of key names (not just values), and maybe you'd like to retrieve the values directly (instead of retrieving the names of the keys that contain them).
- If you have a function that can search key names/values, and retrieve key names/values, and the default is to search for values and retrieve key names, this is cognitively confusing, it's hard to remember which way round it is. So it's better to make them both apply to keys or to values by default. Searching and retrieving values is more useful as the default. This can be very useful when comparing lists of items stored as values in an array.

Code: Select all

q:: ;test object get keys/values
oEven := {}
oSquare := {}
while (vIndex := (A_Index-1) * 2) <= 100
	oEven.Push(vIndex)
while (vIndex := (A_Index-1) ** 2) <= 100
	oSquare.Push(vIndex)

MsgBox, % JEE_StrJoin(" ", oEven*)
MsgBox, % JEE_StrJoin(" ", oSquare*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(oSquare, oEven)*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(oEven, oSquare)*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(oEven, oSquare, "B"))
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(oEven, oSquare, "C"))
MsgBox

MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","ca","ce","dc","e"], ["c","e"], "RV HV SS")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","ca","ce","dc","e"], ["c","e"], "RV HV SE")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","ca","ce","dc","e"], ["c","e"], "RV HV SX")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","ca","ce","dc","e"], ["c","e"], "RV HV SC")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","ca","ce","dc","e"], ["^c.*","e$"], "RV HV SR")*)
MsgBox

MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","b","c","d","e","f"], ["a","c","e"], "RV HV")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","b","c","d","e","f"], ["a","c","e"], "RK HV")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","b","c","d","e","f"], [1,3,5], "RV HK")*)
MsgBox, % JEE_StrJoin(" ", JEE_ObjGetVals(["a","b","c","d","e","f"], [1,3,5], "RK HK")*)
return

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

;options:
;defaults:
;- HV haystacks are values (compare needles against values)
;- RV return values
;- CI case insensitive
;further:
;- B return Boolean
;- C return count
;- L# e.g. L3 limit the number of items counted/returned
;- HK haystacks are key names (compare needles against key names)
;- RK return key names
;- CS case sensitive
;- TN type is numeric (float/integer)
;- TS type is string

;note: vMinKey/vMaxKey may not behave quite like ObjDelete FirstKey/LastKey
JEE_ObjGetVals(ByRef oArray, ByRef oNeedles, vOpt:="", vMinKey:="", vMaxKey:="")
{
	if !IsObject(oNeedles)
		oNeedles := [oNeedles]
	vCount := 0 ;, vLim := -1, vType := "sn"
	vSCS := A_StringCaseSense
	vOpt2 := ""
	Loop, Parse, vOpt, % " "
	{
		vTemp := A_LoopField
		if (vTemp = "B")
			vLim := 1, vRetBool := 1
		if (vTemp = "C")
			vRetCount := 1
		if (SubStr(vTemp, 1, 1) = "L")
			vLim := SubStr(vTemp, 2)
		if (vTemp = "HK") ;haystacks are key names
			vCheckKeys := 1
		if (vTemp = "RK") ;return key names
			vRetKeys := 1
		if (vTemp = "TN")
			vType := "n"
		if (vTemp = "TS")
			vType := "s"
		if (vTemp = "CS") || (vTemp = "SC") || (vTemp = "SS") || (vTemp = "SE") || (vTemp = "SR")
			vOpt2 .= vTemp
	}
	oOutput := {}
	for vKey, vValue in oArray
	{
		if !(vMinKey = "") && (vKey < vMinKey)
			continue
		if !(vMaxKey = "") && (vKey > vMaxKey)
			break
		vHaystack := vCheckKeys ? vKey : vValue

		for _, vNeedle in oNeedles
			;if !(vHaystack <> vNeedle)
			if JEE_StrMatchSingle(vHaystack, vNeedle, vOpt2)
			{
				if (vType="n") && !(Type(vHaystack) ~= "^(Float|Integer)$")
					continue
				if (vType="s") && !(Type(vHaystack) = "String")
					continue
				oOutput.Push(vRetKeys ? vKey : vValue)
				vCount++
				if (vCount = vLim)
					break 2
			}
	}
	StringCaseSense, % vSCS
	if vRetBool
		return !!vCount
	else if vRetCount
		return vCount
	else
		return oOutput
}

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

;not the complete JEE_StrMatch function
;not necessarily the complete JEE_StrMatchSingle function
;note: option CS, does not make RegEx case sensitive
JEE_StrMatchSingle(vText, vNeedle, vOpt:="")
{
	vSCS := A_StringCaseSense
	;On/Off -> Off, Locale -> Locale
	if (A_StringCaseSense = "On")
		StringCaseSense, Off
	Loop, Parse, vOpt, % " `t"
	{
		vTemp := A_LoopField
		if (vTemp = "CS")
			StringCaseSense, On
		if (vTemp ~= "^S[CERSX]$")
			vType := SubStr(vTemp, 2)
		if (vTemp ~= "^[CERSX]$")
			vType := vTemp
	}
	if (vType = "C") ;contains
		vRet := !!InStr(vText, vNeedle)
	else if (vType = "E") ;ends
		vRet := !(SubStr(vText, StrLen(vText)-StrLen(vNeedle)+1) <> vNeedle)
	else if (vType = "R") ;RegEx
		vRet := !!RegExMatch(vText, vNeedle)
	else if (vType = "S") ;starts
		vRet := !(SubStr(vText, 1, StrLen(vNeedle)) <> vNeedle)
	else ;exact (whole)
		vRet := !(vText <> vNeedle)
	StringCaseSense, % vSCS
	return vRet
}

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

JEE_StrJoin(vSep, oArray*)
{
	vOutput := ""
	;if an ObjCount function was available,
	;this would help with estimating the needed capacity,
	;perhaps arrays store data internally that could give an even better estimate
	VarSetCapacity(vOutput, 1000000*2)
	Loop, % oArray.MaxIndex()-1
		vOutput .= oArray[A_Index] vSep
	vOutput .= oArray[oArray.MaxIndex()]
	return vOutput
}

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

;commands as functions (AHK v2 functions for AHK v1) - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=37&t=29689

Type(Value)
{
    local m, f, e
    if IsObject(Value)
    {
        static nMatchObj  := NumGet(&(m, RegExMatch("", "O)", m)))
        static nBoundFunc := NumGet(&(f := Func("Func").Bind()))
        static nFileObj   := NumGet(&(f := FileOpen("*", "w")))
        static nEnumObj   := NumGet(&(e := ObjNewEnum({})))

        return ObjGetCapacity(Value) != ""  ? "Object"
             : IsFunc(Value)                ? "Func"
             : ComObjType(Value) != ""      ? "ComObject"
             : NumGet(&Value) == nBoundFunc ? "BoundFunc"
             : NumGet(&Value) == nMatchObj  ? "RegExMatchObject"
             : NumGet(&Value) == nFileObj   ? "FileObject"
             : NumGet(&Value) == nEnumObj   ? "Object::Enumerator"
             :                                "Property"
    }
    else if (ObjGetCapacity([Value], 1) != "")
        return "String"
    else
        return InStr(Value, ".") ? "Float" : "Integer"
}
- Btw one code trick:

Code: Select all

if (a = b) ;case insensitive
if (a == b) ;case sensitive
if !(a <> b) ;depends on A_StringCaseSense
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 “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 198 guests