judge var isArray or isObject?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
hyaray
Posts: 85
Joined: 20 Jun 2015, 01:37
Contact:

judge var isArray or isObject?

07 May 2019, 02:12

I want a function "getType", Thanks!! :wtf: :wtf:

Code: Select all

getType([1,2]) ;return "Array"

Code: Select all

getType({"a":"aa", "b","bb"}) ;return "Object"
Klarion
Posts: 176
Joined: 26 Mar 2019, 10:02

Re: judge var isArray or isObject?

07 May 2019, 03:54

I do not know the real differencies between Array and Object in AHK
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: judge var isArray or isObject?

07 May 2019, 04:14

Perhaps something like this for IsArray. If anyone can point out any improvements, please do.

Code: Select all

;requires AHK v1.1.29+
;has integer keys 1 to n with no gaps, or is an empty object
IsArray(oArray)
{
	local
	if !ObjCount(oArray)
		return 1
	if !(ObjCount(oArray) = ObjLength(oArray))
	|| !(ObjMinIndex(oArray) = 1)
		return 0
	for vKey in oArray
		if !(vKey = A_Index)
			return 0
	return 1
}
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: judge var isArray or isObject?

07 May 2019, 04:47

You could have: non-integer key count = gap count.

Code: Select all

oArray := ["a", "b", "c"]
MsgBox, % oArray.Length() " " oArray.Count() ;3 3
oArray := {1:"a", 3:"c", x:"x"}
MsgBox, % oArray.Length() " " oArray.Count() ;3 3
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: judge var isArray or isObject?

07 May 2019, 04:52

well what is an array really. id probably check if the first element's key is at least >1 and then check if all elements' keys are numbers.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: judge var isArray or isObject?

07 May 2019, 05:11

'ARRAY'
- The AHK Array function creates objects with keys 1 to n, with no gaps.
- (Typically, arrays in programming languages are objects with keys 0 to n, with no gaps.)

AN AHK OBJECT CONTAINING INTEGERS ONLY
- It might be useful to be able to identify AHK objects where all the keys are integer keys, and where gaps are allowed. An AHK for loop lists integer keys first, so you could do a loop and check until you reach MaxIndex, and if there was at least one more key after that, that would be a non-integer key.

IS IT AN AHK OBJECT
- Here is a test to see if something is a basic AHK object:
type(v) for v1.1 - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=2306
ObjGetCapacity(x) != ""
- (The IsObject function checks if something is an object, not if it is an object capable of being created by the Object function.)
- (In AHK v1, Array() / [] / Object() / {}, use the same object type.)
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
MrDoge
Posts: 160
Joined: 27 Apr 2020, 21:29

Re: judge var isArray or isObject?

14 Dec 2021, 20:18

another method, after fiddling

delete all integer keys, if the amount deleted is the same as .Count(), then it's an Array

Code: Select all

isArray(arrOrObj) { ; https://www.autohotkey.com/boards/viewtopic.php?f=76&t=64332
    return arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == arrOrObj.Count()
}
the above won't work for [ ] because arrOrObj.MaxIndex() will be "", and that's invalid argument for .Delete()
use this one instead: this also includes all the checking by jeeswg (thank you)

Code: Select all

isArray(arrOrObj) { ; https://www.autohotkey.com/boards/viewtopic.php?f=76&t=64332
    return !ObjCount(arrOrObj) || ObjMinIndex(arrOrObj) == 1 && ObjMaxIndex(arrOrObj) == ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}
___
my benchmarks for micro-optimization:
ObjMinIndex(arrOrObj) is a bit faster than arrOrObj.MinIndex()

Code: Select all

#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#SingleInstance, force
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines, -1
#KeyHistory 0
ListLines Off

Frequency := 0
Before := 0
After := 0
DllCall("QueryPerformanceFrequency", "Int64*", Frequency)
DllCall("QueryPerformanceCounter", "Int64*", Before)

; dontModifyThis:={1:"a", 2:"b", "3":"c", 5:"x", x:"5"}
dontModifyThis:={x:"5"}
loop 10000 {
    dontModifyThis.Push(A_Index)
}
; dontModifyThis[dontModifyThis.Count() + 1]:=true
; d(ObjCount(dontModifyThis) ", " ObjLength(dontModifyThis))

; MsgBox % isItArray2(dontModifyThis)

QPC(1)
sleep, 1000 ;0.988971
testN := QPC(0), QPC(1)

loop 10000 {
    if (JEE_IsArray(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
testJEE := QPC(0), QPC(1)

loop 10000 {
    if (isItArray1(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test1 := QPC(0), QPC(1)

loop 10000 {
    if (isItArray2(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test2 := QPC(0), QPC(1)

loop 10000 {
    if (isItArray3(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test3 := QPC(0), QPC(1)

loop 10000 {
    if (isItArray4(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test4 := QPC(0), QPC(1)

loop 10000 {
    if (isItArray5(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test5 := QPC(0), QPC(1)

loop 10000 {
    if (isItArray6(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
test6 := QPC(0), QPC(1)

loop 10000 {
    if (isItArrayCorrect(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
testCorrect := QPC(0), QPC(1)

loop 10000 {
    if (isItArrayObjF(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
testObjF := QPC(0), QPC(1)

loop 10000 {
    if (isItArrayObjFo(dontModifyThis)!=0) {
        MsgBox "Error 2"
    }
}
testObjFo := QPC(0), QPC(1)

d([testJEE, test1, test2, testObjF, testObjFo, test3, test4, test5, test6, testCorrect, testN])
d(dontModifyThis)
; 0.010993
; 0.445327
; 0.290402
; 0.281568
; 0.290992
; 0.009780
; 0.008286
; 0.008505
; 0.008501
; 0.009243
; 0.986390
Exitapp

isItArray1(arrOrObj) {
    return arrOrObj.Clone().Delete(arrOrObj.MinIndex(), arrOrObj.MaxIndex()) == arrOrObj.Count()
}

isItArray2(arrOrObj) {
    return arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == arrOrObj.Count()
}

isItArrayObjF(arrOrObj) {
    return ObjDelete(ObjClone(arrOrObj), 1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}

isItArrayObjFo(arrOrObj) {
    return arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}

isItArray3(arrOrObj) {
    return arrOrObj.MinIndex() == 1 && arrOrObj.MaxIndex() == arrOrObj.Count() && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == arrOrObj.Count()
}

isItArray4(arrOrObj) { ;fastest
    return ObjMinIndex(arrOrObj) == 1 && ObjMaxIndex(arrOrObj) == ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}

isItArray5(arrOrObj) {
    return ObjMinIndex(arrOrObj) = 1 && ObjMaxIndex(arrOrObj) = ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) = ObjCount(arrOrObj)
}

isItArray6(arrOrObj) {
    return ObjMinIndex(arrOrObj) == 1 && ObjMaxIndex(arrOrObj) == ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, ObjMaxIndex(arrOrObj)) == ObjCount(arrOrObj)
}

isItArrayCorrect(arrOrObj) {
    return !ObjCount(arrOrObj) || ObjMinIndex(arrOrObj) == 1 && ObjMaxIndex(arrOrObj) == ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}

JEE_IsArray(oArray)
{
    local
    if !ObjCount(oArray)
        return 1
    if !(ObjCount(oArray) = ObjLength(oArray))
        || !(ObjMinIndex(oArray) = 1)
    return 0
    for vKey in oArray
        if !(vKey = A_Index)
        return 0
    return 1
}

QPC(R := 0)
{
    static P := 0, F := 0, Q := DllCall("QueryPerformanceFrequency", "Int64P", F)
    return ! DllCall("QueryPerformanceCounter", "Int64P", Q) + (R ? (P := Q) / F : (Q - P) / F)
}

f3::Exitapp
this method is stable time
it is slower than JEE_IsArray() if the non-Integer key is at the start
it is way faster if non-Integer key is at the end
at the middle I haven't tested yet

___
tests: please add more if found

Code: Select all

assert(isArray([]),                      1) ;1
assert(isArray([1,2,3]),                 1) ;1
assert(isArray({1:1, 3:3, 4:4}),         0) ;0
assert(isArray({1:"a", 3:"c", x:"x"}),   0) ;0
assert(isArray({1:"a", "2":"b", 3:"c"}), 0) ;0

assert(isArray([1,2,3]), 0) ;1 this should throw, to test my assert function :)

isArray(arrOrObj) { ; https://www.autohotkey.com/boards/viewtopic.php?f=76&t=64332
    return !ObjCount(arrOrObj) || ObjMinIndex(arrOrObj) == 1 && ObjMaxIndex(arrOrObj) == ObjCount(arrOrObj) && arrOrObj.Clone().Delete(1, arrOrObj.MaxIndex()) == ObjCount(arrOrObj)
}

assert(actual, expected) {
    if !(actual==expected)
        MsgBox % "Line " Exception("", -1).Line " Failed`nactual:      " actual "`nexpected: " expected
    ;https://www.autohotkey.com/board/topic/71487-can-a-function-grab-the-calling-lines-line-number/#post_id_453358
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Anput, mcd, Nerafius, RandomBoy, Rohwedder and 101 guests