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"
}
Code: Select all
if (a = b) ;case insensitive
if (a == b) ;case sensitive
if !(a <> b) ;depends on A_StringCaseSense