Page 1 of 2

Array/object wishlist (count, printarr, contains, other).

Posted: 13 Apr 2015, 10:52
by tidbit
Here is my wishlist for arrays/objects. These are things I (and most likely others) often need.
Another topic from 2011 with some requests (which also show I'm not the only one who wants/needs these) http://www.autohotkey.com/board/topic/7 ... min/page-2

wish list:
.count() ; this is what I'd expect .length() to do, but since it doesn't, .count() could exist aswell
counts the number of items in an array or object, regardless of type.

Code: Select all

z:={"aaa":"bbb","ccc":"ddd","yyy":"zzz"}
a:={"aaa":"bbb","ccc":"ddd",111:222}
b:={1:2,3:4,9:10}
c:=[1,2,3,4,20]
d:=["a","b","c","d","e"]

; c=count
for k in z
	cz++
for k in a
	ca++
for k in b
	cb++
for k in c
	cc++
for k in d
	cd++
	
msgbox, % "Maxi() `t len() `t Expected # `t for-loop"
   . "`n" z.maxIndex() " `t " z.length() " `t Expected: 3 `t " cz
   . "`n" a.maxIndex() " `t " a.length() " `t Expected: 3 `t " ca
   . "`n" b.maxIndex() " `t " b.length() " `t Expected: 3 `t " cb
   . "`n" c.maxIndex() " `t " c.length() " `t Expected: 5 `t " cc
   . "`n" d.maxIndex() " `t " d.length() " `t Expected: 5 `t " cd
   . "`n`nI'd expect .length() to return the # of items in an object OR array, no matter the contents. A for-loop should not be needed for such a common task. You should be able to use it inline any function or expression."
contains(mixed, list*) ; found in String Things ( http://ahkscript.org/boards/viewtopic.p ... 3&start=20 )
does an array/object/variable contain any of the specified values? return 1!

Code: Select all

st_contains(mixed, lookFor*)
{
   if (IsObject(mixed))
   {
      for key1,input in mixed
         for key,search in lookFor
            if (InStr(input, search))
               Return 1
   }
   Else
   {
      for key,search in lookFor
         if (InStr(mixed, search))
            Return 1
   }
   Return 0
}
.find(value)
does an array/object have this value? return the key name/number!
.clone()
(aka: deep copy, deep clone, full clone, various other names)
many people, people such as
uname: http://www.autohotkey.com/board/topic/1 ... /?p=638500
GeekDude: http://www.autohotkey.com/board/topic/8 ... -and-more/
various others and myself,
have made functions for this. IMO, this is the behaviour I and many other expect clone() to do.
Just a function to make a quick copy or backup of an array/object without it ever being modified by its parent or it modifying its parent. A completely different thing.
printarr(arr, depth=5) ; found in String Things ( http://ahkscript.org/boards/viewtopic.p ... 3&start=20 )
return the structure of an array/object, up to N dimensions, as a string.
I use this SO MUCH. It's so handy for debugging.

Code: Select all

st_printArr(array, depth=5, indentLevel="")
{
   for k,v in Array
   {
      list.= indentLevel "[" k "]"
      if (IsObject(v) && depth>1)
         list.="`n" st_printArr(v, depth-1, indentLevel . "    ")
      Else
         list.=" => " v
      list.="`n"
   }
   return rtrim(list)
}

Code: Select all

; this version is by AfterLemon is shorter and better. But it's also pretty buggy.
; It also looks nicer. However, I keep both versions available since it's quite
; hard to read :D
st_printArr(array,depth:=10,indentLevel:="     ")
{	static parent,pArr,depthP=depth
	For k,v in (Array,(!IsObject(pArr)?pArr:=[]:""))
	{	Loop,% ((d2=depth&&dP2=depthP)?0:(depth-depthP+1,d2:=depth))
			parent:=SubStr(a:=SubStr(parent,1,InStr(parent,",",0,0)-1),1,InStr(a,",",0,0)),dP2:=depthP++
		k:=RegExReplace(k,","),list.=(indentLevel "arr[" pArr[depth]:=parent (k&1=""?"""" k """":k) "]"),((IsObject(v)&&depth>1)?(parent.=k ",",list.="`n" st_printArr(v,(depthP:=depth)-1,indentLevel "    ")):list.=" = " v),list.="`n"
	}return RTrim(list,"`n")
}
example:
msgbox % st_printArr([11,{"key":"val","key2":"val2"}, 22,33]) ; using Afterlemons
ouputs something like:

Code: Select all

arr[1] = 11
arr[2]
    arr[2,"key"] = val
    arr[2,"key2"] = val2
arr[3] = 22
arr[4] = 33
Object.Key(N) / Array.Key(N)
Retrieve the specified key name, without a for-loop or confusing _NewEnum().Next().
If it's an array, you might have values with gaps between array indexes (not 1,2,3,4 but 1,3,23,75), however, that doesn't make the array 75 items long. It's 4 items with a maxIndex of 75. Doing arr.key(4) would return 75 because 75 is the index/key name of the 4th item.

Code: Select all

stuff:={"aaa":"bbb", "111":"222"}
arr:=[], arr[1]:=111, arr[2]:="xxx", arr[23]:=333, arr[75]:="zzz"

stuff._NewEnum().next(key,val)
msgBox % key ; but how could I get "aaa"?

; What I would like:
; Get the keys name of the specified item.
; msgBox % stuff.key(1) ; --> aaa
; msgBox % stuff.key(2) ; --> 111
; msgBox % arr.key(4) ; --> zzz
Thanks for reading :)

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 13 Apr 2015, 11:01
by Coco
For .Count(), you can do count := NumGet(&obj + 4*A_PtrSize) OR bind it like: ObjCount := Func("NumGet").Bind(4 * A_PtrSize), ObjCount.Call( &obj ) ; must pass object address though. FYI: (took this from lexikos, Obj.Length()/Count() thread some while ago)

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 13 Apr 2015, 11:16
by tidbit
that is not really... obvious at all for new people learning arrays or people who have no clue what that even means but just want to access a common function (atleast in the languages I've used) for arrays.

edit:
IRC wrote:[15-04-13 16:06:29] Bugz000 : this st_printarr function is awesome for debugging this
[15-04-13 16:06:30] Bugz000 : :o

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 13 Apr 2015, 11:24
by Coco
tidbit wrote:that is not really... obvious at all for new people learning arrays or people who have no clue what that even means but just want to access a common function (atleast in the languages I've used) for arrays.
Of course, you're right. I would prefer for .Count() to be built in as well.

Just to add, this breaks compatibility, but could be possible for v2: for the in operator:

Code: Select all

bool := value in ObjectOrArray
; OR
KeyOrIndex := value in ObjectOrArray
IMO, looks really good in the "readability" department.

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 13 Apr 2015, 19:39
by lexikos
Would there be a difference in functionality between value in object and object.Contains(value)?

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 14 Apr 2015, 09:42
by tidbit
Well, my contains() wasn't an object.contains(), that way it could replace if var in/contains list aswell as search objects/arrays.

search within an array for any of these.
does this variable contain any of these.

Re: Array/object wishlist (count, printarr, contains, other)

Posted: 14 Apr 2015, 11:01
by Coco-guest
Docs wrote:For the "in" operator, an exact match with one of the list items is required. For the "contains" operator, a match occurs more easily: whenever Var contains one of the list items as a substring.
If implemented as a function/method, the word contains is usable as both in and contains:

Code: Select all

; As 'in'
value := "foo"
bool := Contains(["foo", "bar", "baz"], value)

; As 'contains'
value := "foo`nbar`nbaz"
bool := Contains(value, ["abc", "foo", "bar"])
If used as operator:

Code: Select all

value := "foo"
bool := value in ["foo", "bar", "baz"]

value := "foo`nbar`nbaz"
bool := value contains ["abc", "foo", "bar"]
As separate functions:

Code: Select all

value := "foo"
ObjContains(["foo", "bar", "baz"], value)
; OR
StrIn(value, ["abc", "foo", "bar"])

str := "foo`nbar`nbaz"
StrContains(str, ["abc", "foo", "bar"])

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 10:40
by tidbit
New entry added, had a need for this on several occasions.
Object.Key(N) / Array.Key(N)
Retrieve the specified key name, without a for-loop or confusing _NewEnum().Next() (which doesn't always work).
If it's an array, you might have values with gaps between array indexes (not 1,2,3,4 but 1,3,23,75), however, that doesn't make the array 75 items long. It's 4 items with a maxIndex of 75. Doing arr.key(4) would return 75 because 75 is the index/key name of the 4th item.

Code: Select all

stuff:={"aaa":"bbb", "111":"222"}
arr:=[], arr[1]:=111, arr[2]:="xxx", arr[23]:=333, arr[75]:="zzz"

stuff._NewEnum().next(key,val)
msgBox % key ; but how could I get "aaa"?

; What I would like:
; Get the keys name of the specified item.
; msgBox % stuff.key(1) ; --> aaa
; msgBox % stuff.key(2) ; --> 111
; msgBox % arr.key(4) ; --> zzz

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 10:59
by guest3456
tidbit wrote:New entry added, had a need for this on several occasions.
Object.Key(N) / Array.Key(N)
I guess if you expect the array to always have ordered keys, then it works.

But in your stuff object, whos to say that "aaa" is the 1st key and "111" is the 2nd key? Should it be based alphabetically? Or should it be based on the order that you personally defined it? Can the parser even determine that?

Can you give some examples where you needed this? I'm having a hard time. Seems like it would be poor practice to do this.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 12:02
by tidbit
the most recent example forced me to use a 3D(?) array.
I wanted an array of various unit types (distance, speed, weight, etc) But due to the auto-sorting system I needed to use an array to have keys in a certain order.

Code: Select all

units:={"Distance":[{"Foot [Ft]":1}
, {"Inch [In]":12}
, {"Yard [Yd]":0.3333}
, {"Mile [Mi]":0.000189394}]}

ccc:=units["distance",3]._NewEnum().next(aaa,bbb)
msgBox % ccc ": " aaa "=" bbb
{typesList[sublist{item:info}]}

a bunch of 1-item objects in the inner-most field
I could do something like: units:={"Distance":["Foot [Ft]|1"]}, ....] and then split by |, but that seems pointless and wasted space needing to split by | and creating another array.

Why is needing to get the key name of a single item "poor practice"? For-loop has it. Is getting a single key only proper in bulk? If you have the info stored, there should be a way to easily retrieve it. Key or value. both sides are important and can be used to store, get and check info. If you build a list using auto-sort in mind (because sorted data can be nice) and you'd like the name/value of the N'th (first, last, anything between) item but not anything before/after it, such a thing would be handy.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 16:32
by guest3456
When your logic is so complex that you need a 3d object, then maybe you should try to see how you can restructure the objects. You have an object with one key "Distance" with the value of an array of objects each with one key. Thats kinda ridiculous, and thats what I mean when I said poor practice. Seems like thats better suited to "Ask for help" and seeing a better way to structure the code.

I don't see how your example proves the need for this. If you want to return the "yards" value, then just query it. MsgBox, % units.Distance.3["Yard [Yd]"]

Why do you need keys in a certain order? Since you've created the object, then you should already know the names of the keys. If you know that "yards" is gonna be the 3rd key, then just create a linear array instead of using an object with string keynames

Its like saying you need:

Code: Select all

myvar1 := "hello"
myvar2 := "world"

MsgBox, % global_vars_array.getName(1)   ;// should output "myvar1"

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 18:15
by tidbit
I was (still might. not sure) going to remake something I made in ahk basic ~5 years ago (which works perfectly, using pseudo-arrays):
http://i.imgur.com/BFr2Mjj.png

I could do something like distance:=[...] speed:=[...] make a bunch of 2D arrays) and call it with %unitList%[], but that doesn't seem like a better solution, especially with how many people are against "dynamical variables" and some want them removed in 2.0. Make a dozen+ 2D arrays just to avoid a 3D array (or if ahk didn't auto-sort, it'd only be 2D, but I'd still need the key names)? No thanks.

I will not be able to hard-code in names as they (each row) will be dynamically renamed and updated with each group. some rows will also be hidden an shown on smaller/larger lists.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 13 May 2015, 19:35
by guest3456
Well that does look like it could contain a lot of levels. Perhaps you could store forumlas instead of hardcoded values. I don't know. There's gotta be a better way.

As for what you call "dynamical variables", I assume you mean double dereferences. I wasn't aware that anyone suggested removing those. They are similar to multiple pointers in C. I'm pretty sure most languages have them.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 14 May 2015, 08:21
by Elesar
Another function to print arrays, that I wrote a few months back (didn't know about tidbit's or Afterlemon's until this thread :P ). My version doesn't have the depth control, but instead returns the entire array/object.

A native implementation of something similar would be very useful IMO, as it is obvious that it is needed by the existence of at least 3 different versions by users.

Code: Select all

enumObj(Obj, indent := 0){
	srtOut := ""
	for key, val in Obj
	{
		if isObject(val)
		{
			loop, %indent%
				strOut .= A_Tab
			strOut .= key . ":`n" . enumObj(val, indent + 1)
		}
		else
		{
			loop, %indent%
				strOut .= A_Tab
			strOut .= key . ": " . val . "`n"
		}
	}
	return strOut
}

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 02 Jul 2015, 16:35
by tidbit
ran into this need for .key a couple times lately:

Due to the Objects auto-ABC sort, I need to turn 1D arrays into 2D arrays.
Each sub-array only consists of 1 array/object.


Usage: I have a treeview and a listbox. I can add items from the treeview to the listbox, when added to the LB, add to an object aswell. Something like: {TV_ID : TV_TEXT}. But since I want it in the order of which it's added to the LB (incase I need to rebuild the LB, if I delete an item), I need to make it a 2D Array, to avoid auto-sorting.

Code: Select all

arr:=[{"437742":"first"},{"122516":"second"},{"472125":"third"}]

; instead of this for every part I go through the array (this gets messier when other {}'s are needed for the for-loops):
for key, arr2 in arr
	for key, val in arr2
		msgBox, %key% = %val%

; it'd simply be:
for key, arr2 in arr
	msgBox, % arr2.key(1) " = " arr2.value(1)
	
; or if I only need the 3rd item from the list
msgbox % arr[3].key(1 " = " arr[3].value(1))

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 02 Jul 2015, 22:03
by lexikos
Something like: {TV_ID : TV_TEXT}
Why? Just use [TV_ID, TV_TEXT], or an associative array with known keys of your choosing.

The order of keys in an object is officially undefined; the order in which the keys were originally assigned is not stored anywhere. It would not be sensible to provide a method for returning the nth key in undefined order.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 29 Oct 2015, 13:11
by mmartin1212
These should be included in AHK!

st_PrintArr() is invaluable to debugging in depth arrays.

I was able to troubleshoot a problem that I spent 4 hours on in 15 minutes with that function.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 12 Jan 2016, 13:58
by howdoesexcelwork
Bump for the ba$ed print array function

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 12 Jan 2016, 18:28
by nnnik
Elesar wrote:Another function to print arrays, that I wrote a few months back (didn't know about tidbit's or Afterlemon's until this thread :P ). My version doesn't have the depth control, but instead returns the entire array/object.

A native implementation of something similar would be very useful IMO, as it is obvious that it is needed by the existence of at least 3 different versions by users.
I also have a Version of that and yes I agree.
It shouldn't be impossible to distribute an AutoHotkey function with AutoHotkey.
If it is defined like a normal standard AHK function it wouldn't collide with already created Scripts.

Re: Array/object wishlist (count, printarr, contains, other).

Posted: 20 Jan 2016, 11:31
by -_+
+1 vote to make Obj.Count() work predictably (count the total number of items in the array) for associative arrays.
As for printarr() I also suggest another solution: pick something like JSON as a standard and add built-in support of object <> JSON encoding/decoding.
JSONed objects + beautify = a pretty readable debug output.