Skip to content

Instantly share code, notes, and snippets.

@errorseven
Last active March 17, 2019 11:33
Show Gist options
  • Save errorseven/660178adcc754fd9a7c1b1ff22852167 to your computer and use it in GitHub Desktop.
Save errorseven/660178adcc754fd9a7c1b1ff22852167 to your computer and use it in GitHub Desktop.
Zero Based Array's with Python functionality for AutoHotkey
/*
___ _ _ _ _ _
/ _ \ _ _ | |_ | |__ /_\ | |__ | | __
/ /_)/ | | | | | __| | '_ \ //_\\ | '_ \ | |/ /
/ ___/ | |_| | | |_ | | | | / _ \ | | | | | <
\/ \__, | \__| |_| |_| \_/ \_/ |_| |_| |_|\_\
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