[AHK v2] Function Broadcast to Array/Object

Post your working scripts, libraries and tools
oif2003
Posts: 137
Joined: 17 Oct 2018, 11:43
GitHub: oif2003

[AHK v2] Function Broadcast to Array/Object

16 Nov 2018, 18:45

Hi,

Here is a broadcasting function (db) that allows the use of functions on elements of an array or object. If desired depth is not specified, it will iterate over each non-object elements and return an object with the same structure. If depth is specified, it will pass the object found at that level to the provided function. Combine this with the list function (ls), which lists all elements of an n-dimensional array, it can potentially save a lot of time in writing (nested) loops. See code for example and usage. (Note: this is written for AutoHotkey v2)

https://github.com/oif2003/AHK_v2_64bit ... t.ahk?ts=4

Code: Select all

#SingleInstance Force

arr1 := [	  
			  [11, 12, 13, 14, 15]
			, [21, 22, 23, 24, 25]
			, [31, 32, 33, 34, 35]
			, [41, 42, 43, 44, 45]
		]

arr2 := [	  
			  [11, 12]
			, [21, 22]
			, [31, 32]
		]

arr3 := [	  
			  [[111,112], [221,222]]
			, [[211,212], [221,222]]
			, [[311,312], [321,322]]
		]

obj := 	{	  mon:{breakfast:6.5, lunch:11.5, dinner:18}
			, tue:{breakfast:6, lunch:11, dinner:18.5}
			, wed:{breakfast:7, lunch:12.5, dinner:19}
			, thu:{breakfast:6.5, lunch:12, dinner:17.5}
			, fri:{breakfast:6, lunch:11, dinner:18}
			, sat:{breakfast:8, lunch:13.5, dinner:20}
			, sun:{breakfast:9, lunch:13, dinner:19}
		}

pn("Content of arr1:")
p(arr1), pn()

pn("Multiply each element by 10")
test2 := db(arr1, (x) => x * 10)		;when depth is left blank defaults to max
p(test2), pn("`n-----------------------------------------------------------------------------------------------------------------")

pn("Content of arr2:")
pn("(each row corresponds to possible values for x, y, z respectively)")
p(arr2), pn()

pn("Calculate distance from the origin on (x, y, z) sets defined by arr2")
list := ls(arr2)					;generate 1D array with list of points/coordinates
test3 := db(list, (x)=>dist(x*), 1)	;broadcast distance function to list
p(test3, 1), pn("`n-----------------------------------------------------------------------------------------------------------------")

pn("Content of arr3:")
p(arr3), pn()

pn("Variadic function sum test: 2 levels deep")
test4 := db(arr3, (x) => sum(x*), 2)	;goes down two levels
p(test4), pn()

pn("Deep copy of arr3")
test5 := db(arr3)	;when funtion is not provided, returns deep copy of array
p(test5), pn("`n-----------------------------------------------------------------------------------------------------------------")

pn("Content of obj:")
p(obj, 1), pn()

pn("Convert hours to HH:MM format in obj")
test6 := db(obj, (x) => formatHours(x))	;iterate over all elements
p(test6, 1)

;functions used in the above examples
dist(x*) {
	sum := 0
	for _, v in x
		sum += v*v
	return format("{:.2f}", sqrt(sum))
}
sum(x*) {
	s := 0
	for _, v in x
		s += v
	return s
}
formatHours(h) {
	m := (h - floor(h)) * 60
	return format("{1:02d}:{2:02d}", floor(h), m)
}

;------------------------------------------------------------
;deep broadcast for n levels
; a = array/object
; f = function (default is none, which performs a deep copy)
; n = depth (default is max)
; last parameter is for internal use only
db(a, f := "", n := 0x7FFFFFFF, run1 := true) {
	static _n
	if run1
		_n := 1
	
	if _n <= n && isObject(a) {
		_n++, b := {}		
		for k, v in a
			b[k] := db(v, f, n, false)
		return (_n--, b)
	}
	else
		if f != ""
			return f.call(a)
		else return a
}
;by reference version of db, f must not be blank
dbr(a, f := "", n := 0x7FFFFFFF, run1 := true) {
	static _n
	if run1
		_n := 1
	
	if _n <= n && isObject(a) {
		_n++		
		for k, v in a
			a[k] := dbr(v, f, n, false)
		return (_n--, a)
	}
	else
		return f.call(a)
}

;------------------------------------------------------------
;list all elements
; a = array/object
; second parameter is for internal use only
ls(a, run1 := true) {		
	static r, t 		
	if run1	
		r := [], t := [] 
	
	b := a.Clone()
	if b.length()		
		for k, v in b.pop()	
			t.InsertAt(1, v), ls(b, false) 	
	else						
		if !r.length()			
			r.push(t), t := []			
		else {					
			_t := r[r.push()].Clone()		
			loop t.length()		
				_t[A_Index] := t[A_Index]	
			r.push(_t), t := []			
		}						
	return r				
}

;----------------------------------------------------------------------
;Just a print functions, nothing interesting here
pn(x:="") => p(x "`n")
p(x, opt := 0) {
	isObject(x) ? (opt ? po(x) 
					   : pa(x))
			    : _p(x) 
	
	;GUI EditBox print
	_p(x) {
		static gui, eb1, eb2, tb

		if !isObject(gui)
			  gui := GuiCreate("+resize", A_ScriptFullPath)
			, tab := gui.Add("Tab3", , "Default|Overflow")
			, tab.UseTab("Default")
			, eb1 := gui.Add("Edit", "r50 w800 +readonly -E0x200")
			, tab.UseTab("Overflow")
			, eb2 := gui.Add("Edit", "r50 w800 +readonly -E0x200")
			, Tab.UseTab()
			, aot := gui.Add("CheckBox", , "Always On Top")
			, gui.onEvent("Size",  ()=>onResize())
			, aot.onEvent("Click", ()=>WinSetAlwaysOnTop(aot.value, "ahk_id" gui.hwnd))
			, gui.show()
			, onResize()
		
		if StrLen(tb) > 1000
			eb1.value .= tb, PostMessage(0x115, 7, , eb1.hwnd, "ahk_id" gui.hwnd), tb := ""
		
		tb .= x, prevtb := tb, SetTimer(()=>update(), -50)
		update() {
			if tb == prevtb {
				if StrLen(eb1.value) > 100000
					  eb2.value .= eb1.value
					, eb1.value := ""
				  eb1.value .= tb, PostMessage(0x115, 7, , eb1.hwnd, "ahk_id" gui.hwnd)
				, tb := ""
			}
		}
		
		onResize() {
			  tab.move("x2 y2 w" (gui.ClientPos.w - 3) " h" (gui.ClientPos.h - 4))
			, eb1.move("x0 y0 w" (gui.ClientPos.w - 8) " h" (gui.ClientPos.h - 24))
			, eb2.move("x0 y0 w" (gui.ClientPos.w - 8) " h" (gui.ClientPos.h - 24))
			, aot.move("x" (gui.ClientPos.w - 100) " y" gui.MarginY - 1)
		}
	}
	
	;Print 1D or 2D array, if Dim > 2, print as object
	pa(a) {
		for _, v in a
			if isObject(v) && dim < 2 && dim := 2
				for _, s in v
					isObject(s) && dim < 3 && dim := 3
		if dim == 3
			po(a)		
		else if dim == 2
			for k, v in a
				p("[" k "] "), _pa(v)
		else
			_pa(a)
		
		;helper function for printing 1D array
		_pa(a) {
			for k, v in a
				r .= (k == 1 ? "" : ",") v
			pn("[" r "]")
		}
	}

	;Print object recursively
	po(o, tablevel := 0) {
		static more := true
		
		loop tablevel
			tab .= "`t"
		if isObject(o) {
			  more := true
			, tablevel && pn()
			for k, v in o
				  p(tab "[" k "]")
				, po(v, tablevel + 1)
				, more && pn()
		}
		else 
			  pn(" = " o)
			, more := false
	}
}
Output:

Code: Select all

Content of arr1:
[1] [11,12,13,14,15]
[2] [21,22,23,24,25]
[3] [31,32,33,34,35]
[4] [41,42,43,44,45]

Multiply each element by 10
[1] [110,120,130,140,150]
[2] [210,220,230,240,250]
[3] [310,320,330,340,350]
[4] [410,420,430,440,450]

-----------------------------------------------------------------------------------------------------------------
Content of arr2:
(each row corresponds to possible values for x, y, z respectively)
[1] [11,12]
[2] [21,22]
[3] [31,32]

Calculate distance from the origin on (x, y, z) sets defined by arr2
[1] = 39.03
[2] = 39.32
[3] = 39.57
[4] = 39.86
[5] = 39.82
[6] = 40.11
[7] = 40.36
[8] = 40.64

-----------------------------------------------------------------------------------------------------------------
Content of arr3:
[1]
	[1]
		[1] = 111
		[2] = 112
	[2]
		[1] = 221
		[2] = 222
[2]
	[1]
		[1] = 211
		[2] = 212
	[2]
		[1] = 221
		[2] = 222
[3]
	[1]
		[1] = 311
		[2] = 312
	[2]
		[1] = 321
		[2] = 322

Variadic function sum test: 2 levels deep
[1] [223,443]
[2] [423,443]
[3] [623,643]

Deep copy of arr3
[1]
	[1]
		[1] = 111
		[2] = 112
	[2]
		[1] = 221
		[2] = 222
[2]
	[1]
		[1] = 211
		[2] = 212
	[2]
		[1] = 221
		[2] = 222
[3]
	[1]
		[1] = 311
		[2] = 312
	[2]
		[1] = 321
		[2] = 322

-----------------------------------------------------------------------------------------------------------------
Content of obj:
[fri]
	[breakfast] = 6
	[dinner] = 18
	[lunch] = 11
[mon]
	[breakfast] = 6.5
	[dinner] = 18
	[lunch] = 11.5
[sat]
	[breakfast] = 8
	[dinner] = 20
	[lunch] = 13.5
[sun]
	[breakfast] = 9
	[dinner] = 19
	[lunch] = 13
[thu]
	[breakfast] = 6.5
	[dinner] = 17.5
	[lunch] = 12
[tue]
	[breakfast] = 6
	[dinner] = 18.5
	[lunch] = 11
[wed]
	[breakfast] = 7
	[dinner] = 19
	[lunch] = 12.5

Convert hours to HH:MM format in obj
[fri]
	[breakfast] = 06:00
	[dinner] = 18:00
	[lunch] = 11:00
[mon]
	[breakfast] = 06:30
	[dinner] = 18:00
	[lunch] = 11:30
[sat]
	[breakfast] = 08:00
	[dinner] = 20:00
	[lunch] = 13:30
[sun]
	[breakfast] = 09:00
	[dinner] = 19:00
	[lunch] = 13:00
[thu]
	[breakfast] = 06:30
	[dinner] = 17:30
	[lunch] = 12:00
[tue]
	[breakfast] = 06:00
	[dinner] = 18:30
	[lunch] = 11:00
[wed]
	[breakfast] = 07:00
	[dinner] = 19:00
	[lunch] = 12:30

Return to “Scripts and Functions”

Who is online

Users browsing this forum: OmegaMachine and 27 guests