Last active
March 17, 2019 11:33
-
-
Save errorseven/660178adcc754fd9a7c1b1ff22852167 to your computer and use it in GitHub Desktop.
Zero Based Array's with Python functionality for AutoHotkey
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
___ _ _ _ _ _ | |
/ _ \ _ _ | |_ | |__ /_\ | |__ | | __ | |
/ /_)/ | | | | | __| | '_ \ //_\\ | '_ \ | |/ / | |
/ ___/ | |_| | | |_ | | | | / _ \ | | | | | < | |
\/ \__, | \__| |_| |_| \_/ \_/ |_| |_| |_|\_\ | |
v0.0.0.4 |___/ Coded by errorseven @ 7-9-2016 | |
- Zero Based Array's with Python functionality for AutoHotkey. | |
Credit: | |
Lexikos, Coco, and GeekDude for examples on the official | |
forums of over-riding Array() and Object()! | |
https://autohotkey.com/boards/viewtopic.php?t=5828 | |
https://autohotkey.com/board/topic/83081-ahk-l-customizing-object-and-array/ | |
Update Notes - v0.0.0.4 @ 10-28-2016: | |
1) Added oct(), hex(), improved bin() | |
2) Improved str() now allows you to print arrays, support for Associative | |
arrays is in the works! | |
Update Notes - v0.0.0.3 @ 10-28-2016: | |
1) Added map() and unzip() | |
2) Refactored code throughout. | |
3) Added better discriptions and examples to functions, more to come! | |
*/ | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | |
; CLASSES / METHODS | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | |
class CustomObject extends _Array | |
{ | |
static _ := "".base.base := CustomObject | |
} | |
; Define base class. | |
Class _Array extends _Str { | |
append(x) { | |
return this.push(x) | |
} | |
count(x) { | |
y:=0 | |
for k,v in this | |
if (v == x) | |
y++ | |
return y | |
} | |
index(x) { | |
For k,v in this { | |
if (v == x) | |
return k | |
} | |
} | |
length() { | |
; Most accurate way I could find. | |
c := 0 | |
for k,v in this | |
c++ | |
return c | |
} | |
push(x) { | |
; Zero based push() | |
if (this.0 == "" && this.length() == 0) | |
return this.0 := x | |
else | |
return this[this.length()] := x | |
} | |
reverse() { | |
x := [] | |
loop % this.length() | |
x.append(this.pop()) | |
return x | |
} | |
} | |
; Define the base class. | |
class _Object { | |
Remove(prm*) { | |
if prm.MaxIndex() = 1 { | |
k := prm[1] | |
if k is integer | |
return ObjRemove(k, "") | |
} | |
return ObjRemove(prm*) | |
} | |
} | |
class _str { | |
; +-+-+-+- PROPERTIES +-+-+-+- | |
ascii_letters[] { | |
get { | |
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
} | |
} | |
ascii_lowercase[] { | |
get { | |
return "abcdefghijklmnopqrstuvwxyz" | |
} | |
} | |
ascii_uppercase[] { | |
get { | |
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
} | |
} | |
ascii_vowels[] { | |
get { | |
return "aeiouy" | |
} | |
} | |
ascii_novowels[] { | |
get { | |
return "bcdfghjklmnpqrstvwxyz" | |
} | |
} | |
; +-+-+-+- Methods +-+-+-+- | |
capitalize() { | |
/* | |
Returns a copy of the string with | |
only its first character capitalized. | |
*/ | |
cap := false | |
for e,v in this { | |
if (type(v, "alpha") && cap == false) { | |
r .= Format("{1:U}", v) | |
cap := true | |
} | |
else | |
r .= v | |
} | |
return r | |
} | |
center(width, fillchar:=" ") { | |
/* | |
Returns centred in a string of length width. | |
Padding is done using the specified fillchar. | |
Default filler is a space. | |
*/ | |
pad := round((width - this.length()) // 2) | |
loop % pad | |
r .= fillchar | |
return r this.toString() r | |
} | |
endswith(suffix, beg:=0, end:="") { | |
/* | |
Returns True if the string ends with the specified suffix, | |
otherwise return False optionally restricting the matching | |
with the given indices start and end. | |
*/ | |
if (end == "") | |
end := this.length() | |
for e,v in range(beg, end) | |
r .= this[v] | |
return suffix == r | |
} | |
expandtabs(tabsize:=8) { | |
/* | |
Returns a copy of the string in which tab characters ie. | |
'\t' are expanded using spaces, optionally using the given | |
tabsize (default 8).. | |
*/ | |
loop % tabsize | |
r .= " " | |
return StrReplace(this.toString(), "`t", r) | |
} | |
isupper() { | |
for e,v in this | |
if ("".ascii_uppercase ~= v) | |
return true | |
return false | |
} | |
join(seq) { | |
/* | |
Returns a string in which the string elements of sequence have been | |
joined by string separator. | |
*/ | |
r := "" | |
for e,v in seq { | |
if (e == seq.MaxIndex()) { | |
r .= v | |
break | |
} | |
r .= v this.toString() | |
} | |
return r | |
} | |
ljust(width, fillchar:=" ") { | |
/* | |
Returns string padded on the left | |
with zeros to fill width. | |
*/ | |
pad := abs(width - this.length()) | |
loop % pad | |
r .= fillchar | |
return this.toString() r | |
} | |
rjust(width, fillchar:=" ") { | |
/* | |
Returns string padded on the left | |
with zeros to fill width. | |
*/ | |
pad := abs(width - this.length()) | |
loop % pad | |
r .= fillchar | |
return r this.toString() | |
} | |
slice(start, stop:="", step:=1) { | |
/* | |
Return a slice object representing the set of | |
indices specified by range(start, stop, step). | |
*/ | |
if (stop == "") | |
stop := start, start := 0 | |
if (IsObject(this)) { | |
for e,v in range(start, stop, step) { | |
r .= this[v] | |
} | |
} | |
return r | |
} | |
swapcase() { | |
/* | |
Returns a copy of the string in which all the case-based | |
characters have had their case swapped. | |
*/ | |
for e,v in this | |
if (this.ascii_letters ~= v) | |
r .= (this.ascii_uppercase ~= v ? format("{1:L}", v) | |
: format("{1:U}", v)) | |
else | |
r .= v | |
return r | |
} | |
toString() { | |
; Returns string from str() object | |
for e,v in this | |
r .= v | |
return r | |
} | |
zfill(width) { | |
/* Returns string padded on the left | |
with zeros to fill width. | |
*/ | |
loop % abs(this.length() - width) | |
r .= 0 | |
return r . this.tostring() | |
} | |
} | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | |
; FUNCTIONS | |
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- | |
; Redefine Array() | |
Array(prm*) { | |
/* | |
Since prm is already an array of the parameters, just give it a | |
new base object and return it. Using this method, _Array.__New() | |
is not called and any instance variables are not initialized. | |
Additionally we declare an Object using {} to act as container | |
for our first 0 based Array, if declared as an Array using [] | |
we enter into a infinite loop. Assuming that prm is not empty, | |
otherwise an empty Array is returned and an initial method, push() | |
will set the array at index of 0. | |
*/ | |
x := {} | |
loop % prm.length() | |
x[A_Index -1] := prm[A_Index] | |
x.base := _Array | |
return x | |
} | |
bin(x) { | |
/* | |
Convert an integer number to a binary string. | |
Return: binary str | |
x -> int | |
example: bin(5) -> 0b101 | |
bin(-2398892) -> -0b1001001001101010101100 | |
*/ | |
if (x < 0) | |
neg := True, x := abs(x) | |
While(x != 0) { | |
z := Mod(x, 2) z | |
x := x // 2 | |
} | |
return (neg?"-":_) "0b" ltrim(z, "0") | |
} | |
hex(x) { | |
/* | |
Convert an integer number to a hexcidecimal string. | |
Return: hexcidecimal str | |
x -> int | |
example: hex(22) -> 0x16 | |
*/ | |
if (x < 0) | |
neg := True, x := abs(x) | |
return (neg?"-":_) format("0x{:x}", x) | |
} | |
map(function, iter*) { | |
/* | |
Apply function to every item of iterable and return a array of the | |
result. If additional iterable arguments are passed, function must take | |
that many arguments and is applied to the items from all iterables in | |
parallel. | |
Return: Array | |
function -> str | |
iter -> Varadic | |
example: map("sum", [[2, 4], [3, 1, 5]], [0, 1]) -> [6, 6] | |
map("sum", zip(range(5), range(4))) -> [0, 2, 4, 6] | |
*/ | |
fn := Func(function) | |
if (fn.MinParams > iter.length()) | |
return False | |
for e, v in iter | |
if !(IsObject(iter)) | |
return False | |
z := [], i:=0, n:=1 | |
for e, v in iter { | |
if (e == 1) | |
min := v.length() | |
else | |
min := min > v.length() ? v.length() : min | |
} | |
Loop % min { | |
newArr := [] | |
loop % iter.length() { | |
newArr[A_index] := iter[n][i] | |
n++ | |
} | |
z[A_Index] := newArr, n := 1, i++ | |
} | |
r := [] | |
For e, v in z | |
r.push(fn.call(v*)) | |
return r | |
} | |
oct(x) { | |
/* | |
Convert an integer number to a octal string. | |
Return: octal str | |
x -> int | |
example: oct(23) -> 0o27 | |
*/ | |
if (x < 0) | |
neg := True, x := abs(x) | |
num := power := 0 | |
while (x > 0) { | |
num += 10 ** power * (Mod(x, 8)) | |
x //= 8, power++ | |
} | |
return (neg?"-":_) "0o" num | |
} | |
Object(prm*) { | |
/* | |
Create a new object derived from _Object. | |
*/ | |
obj := new _Object | |
; For each pair of parameters, store a key-value pair. | |
Loop % prm.MaxIndex()//2 | |
obj[prm[A_Index*2-1]] := prm[A_Index*2] | |
; Return the new object. | |
return obj | |
} | |
range(start:="", stop:="", step:=1) { | |
/* | |
Creates an array containing arithmetic progressions. It is most often | |
used in for loops. The arguments must be plain integers. If the step | |
argument is omitted, it defaults to 1. If the start argument is omitted, | |
it defaults to 0. | |
Return: Array | |
start -> int | |
stop -> int | |
step -> int | |
example: range(5) -> [0, 1, 2, 3, 4] || range(0, 7, 2) -> [0, 2, 4, 6] | |
*/ | |
r := [] | |
if (start == "") | |
return | |
if (stop == "") | |
stop:=start,start:=0 | |
if (step == 0) | |
return r | |
if (step < 0) { | |
loop { | |
r.push(start) | |
start += step | |
if (start <= stop) | |
break | |
} | |
} | |
else { | |
loop { | |
r.push(start) | |
start += step | |
if (start >= stop) | |
break | |
} | |
} | |
return r | |
} | |
split(x, dlm:="", opt:="") { | |
/* | |
Zero Based implementation of StrSplit() separates a string into an array | |
of substrings using the specified delimiters. | |
Return: array | |
x -> str | |
dlm -> str | |
opt -> str | |
example: split("abc") -> ["a", "b", "c"] | |
*/ | |
r := [] | |
for e, v in StrSplit(x, dlm, opt) | |
r.push(v) | |
return r | |
} | |
str(prm) { | |
/* | |
Initiates String Class Object / Array | |
granting access to a plethora of String Methods | |
Returns: Class Object | |
prm -> value or object | |
example: str("abc") -> ["a", "b", "c"] | |
x := [1, 2, 3, [4, 5]] | |
str(x).ToString() -> [1, 2, 3, [4, 5]] | |
*/ | |
if (IsObject(prm)) { | |
x .= "[" | |
for e,v in prm { | |
if !(IsObject(v) and !type(e, "alpha")) | |
x .= v ", " | |
else | |
x .= str(v).ToString() | |
} | |
prm := StrReplace(x, "][", "], [") | |
r := split(trim(prm, ", ") "]") | |
return r | |
} | |
r := split(prm) | |
return r | |
} | |
sum(iter, start:=0) { | |
/* | |
Sums start and the items of an iterable from left to right and returns | |
the total. start defaults to 0. The iterable‘s items are normally | |
numbers, and the start value is not allowed to be a string. | |
Return: int or float | |
iter -> Array | |
start -> int | |
example: sum([1, 2 ,3]) -> 6 || sum([1.0, 2.0, 3.0], 1) -> 5.00000 | |
*/ | |
if !(type(iter, "obj")) | |
return | |
r := 0 | |
for e,v in iter | |
if (e >= start) | |
r += v | |
return r | |
} | |
type(var, direct:="") { | |
/* | |
Returns the type of obj/var in the form of a string | |
If direct option is used with a type, it returns True | |
or False. | |
Return: str or bool | |
direct -> str | |
var -> value or object | |
example: type(2, "int") -> True || type(2) -> "int" | |
*/ | |
types := { "float": "float", "alpha": "alpha" | |
, "digit": "int" , "xdigit": "hex" } | |
if (direct != "") { | |
If (IsObject(var) && direct != "obj") | |
return false | |
if (direct == "obj") | |
return (IsObject(var)) | |
else | |
For key, value in types { | |
if (value == direct) { | |
if var is % key | |
return true | |
} | |
} | |
return false | |
} | |
if (IsObject(var)) | |
return "obj" | |
if (var == "") | |
return "null" | |
For key, type in types { | |
if var is % key | |
return type | |
} | |
return "str" | |
} | |
unzip(x) { | |
/* | |
This function is the reverse of zip(). In Python you have a switch | |
option * that you can pass to trigger a reverse response, AHK does not. | |
Return: array | |
x -> array | |
example: unzip([[1, 4], [2, 5], [3, 6]]) -> [[1, 2, 3], [4, 5, 6]] | |
*/ | |
z := [], i:=0 | |
for e,v in x { | |
if (e == 1) | |
min := v.length() | |
else | |
min := min > v.length() ? v.length() : min | |
} | |
loop % min { | |
newArr := [] | |
for e, v in x | |
newArr.push(v[i]) | |
z[i] := newArr, i++ | |
} | |
return z | |
} | |
zip(x*) { | |
/* | |
This function returns an array of arrays, where the i-th array contains | |
the i-th element from each of the argument sequences or iterables. The | |
returned array is truncated in length to the length of the shortest | |
argument sequence. When there are multiple arguments which are all of | |
the same length. | |
Return: array | |
x -> varadic | |
example: zip([1, 2, 3], [4, 5, 6]) -> [[1, 4], [2, 5], [3, 6]] | |
*/ | |
if !(type(x, "obj")) | |
return | |
z := [], i:=0, n:=1 | |
for e,v in x { | |
if (e == 1) | |
min := v.length() | |
else | |
min := min > v.length() ? v.length() : min | |
} | |
k := min | |
Loop % k { | |
newArr := [] | |
loop % x.length() { | |
newArr.push(x[n][i]) | |
n++ | |
} | |
z[i] := newArr, n := 1, i++ | |
} | |
return z | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment