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

Propose new features and changes
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

13 Apr 2015, 10:52

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 :)
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

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

13 Apr 2015, 11:01

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)
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

13 Apr 2015, 11:16

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
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

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

13 Apr 2015, 11:24

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.
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

13 Apr 2015, 19:39

Would there be a difference in functionality between value in object and object.Contains(value)?
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

14 Apr 2015, 09:42

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.
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Coco-guest

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

14 Apr 2015, 11:01

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"])
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

13 May 2015, 10:40

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
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

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

13 May 2015, 10:59

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.

User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

13 May 2015, 12:02

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.
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

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

13 May 2015, 16:32

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"

User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

13 May 2015, 18:15

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.
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

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

13 May 2015, 19:35

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.

Elesar
Posts: 70
Joined: 31 Oct 2013, 07:56

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

14 May 2015, 08:21

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
}
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

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

02 Jul 2015, 16:35

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))
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

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

02 Jul 2015, 22:03

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.
mmartin1212
Posts: 10
Joined: 26 Jul 2015, 03:21

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

29 Oct 2015, 13:11

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.
howdoesexcelwork

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

12 Jan 2016, 13:58

Bump for the ba$ed print array function
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

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

12 Jan 2016, 18:28

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.
Recommends AHK Studio
-_+
Posts: 70
Joined: 06 Dec 2014, 12:43

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

20 Jan 2016, 11:31

+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.

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 36 guests