很多新手入坑后对于Array的操作用不明白,Push、Pop等函数略为抽象,这里提供Array的增强版本,不需要更多的函数引用,在原有的Array基础上,你将有更多的函数用来操作Array数组。
下载地址:
更新时间:2022.09.07
使用介绍:
; 属性
1)Dims——返回Array深度
2)NDim——返回Array深度(与Dims相同)
3)Max——返回Array中最大项
4)MaxDim——返回Array中最大深度
5)MaxDimIndex——返回Array中最大深度对应项
6)Min——返回Array中最小项
7)Product——返回Array所有数字元素之积
8)Shape——返回Array的形状,这一操作会对Array进行规格化
; 函数(为保证完整性,以下函数均会直接改变Array对象本身)
1)Append(Content*)——在Array尾部添加对象,同Push
2)Count(Obj)——返回Array中Obj数量
3)Extend(Extend_Lst*)——在Array尾部延伸输入内容,与Append有区别
4)Index(Obj)——返回Array中Obj首次出现位置,若不存在返回-1
5)Insert(Index, Obj*)——在Array指定位置插入若干对象
6)IReshape(Shape)——将Array重构为Shape形状,这一变形不会对Array进行规格化
7)Reshape(Shape)——将Array重构为Shape形状,这一变形会对Array进行规格化
8)Ravel()——将Array拉伸为一维,这一变形不会对Array进行规格化
9)Standardization()——将Array规格化,Array形状由每一层最大深度确定,缺位补0
10)Item(Pos*)——通过多维方式访问Array
11)SetItem(Pos*, Value)——通过多维方式设置Array项值
12)MaxLength(Dim := 1)——获取Array在某一个Dim的最大长度
13)Remove(Obj*)——移除Array中若干Obj项
14)Reverse()——将Array倒置
15)Swap(Index1, Index2)——将Array中的第Index1和Index2项交换
16)Sort(cmp := "", key := "", reverse := False)——排列Array
cmp默认为升序比较函数(函数参数需要两个,函数返回值大于零表示排列优先)
key默认为空,(函数参数为1个,函数返回值大的表示排列优先)
reverse默认为否,若为真则反转排列后列表
#Include AHKType.ahk
; 测试
a := [1, 2, [3, 4]]
Print(a.Dims)
Print(a.NDim)
a := [1, 2, [3, 4], [5, 6, [7, 8]]]
b := [1, 2, [3, 4], [5, 6, [7, 8]]]
a.Reshape([3, 2, 4])
b.IReshape([2, 4])
Print(a)
Print(b)
a := [1, 2, [3, 4], [5, 6, [7, 8]]]
a.ravel()
Print(a)
; Sort函数测试
a := [2, 1, 4 ,5]
Print(a.Sort("reverse=1"))
b := [2, 1, 4 ,5]
Print(b.Sort())
c := [2, 1, 4 ,5]
Print(c.Sort(comp))
d := ["456", "123", "1237" ,"00"]
Print(d.Sort("key=Len"))
; 上一行等价于Print(d.Sort(, Len))
comp(x, y)
{
if x < y
return 1
else if x > y
return -1
else
return 0
}
Len(x)
{
if x is Array
Return x.Length
else if x is String
Return StrLen(x)
Return x
}
AHKType源码
; Author: Mono
; Time: 2022.09.08
; Version: 1.0.0
#Include Print.ahk
; Init DefProp
DefProp := {}.DefineProp
; Redefine Dims
0.0.Base.Dims := 0
0.Base.Dims := 0
"".Base.Dims := 0
Object().Base.Dims := 0
DefProp([].Base, "Dims", {Get: GetArrDims})
; Redefine NDim
0.0.Base.NDim := 0
0.Base.NDim := 0
"".Base.NDim := 0
Object().Base.NDim := 0
DefProp([].Base, "NDim", {Get: GetArrDims})
; Redefine Array
DefProp([].Base, "Append", {Get: ArrAppend})
DefProp([].Base, "Count", {Get: ArrCount})
DefProp([].Base, "Extend", {Get: ArrExtend})
DefProp([].Base, "Index", {Get: ArrIndex})
DefProp([].Base, "Insert", {Get: ArrInsert})
DefProp([].Base, "IReshape", {Get: ArrIReshape})
DefProp([].Base, "Item", {Get: GetArrItem})
DefProp([].Base, "Max", {Get: GetArrMax})
DefProp([].Base, "MaxDim", {Get: GetArrMaxDim})
DefProp([].Base, "MaxDimIndex", {Get: GetArrMaxDimIndex})
DefProp([].Base, "MaxLength", {Get: GetArrMaxLength})
DefProp([].Base, "Min", {Get: GetArrMin})
DefProp([].Base, "Product", {Get: GetArrProduct})
DefProp([].Base, "Ravel", {Get: ArrRavel})
DefProp([].Base, "Remove", {Get: ArrRemove})
DefProp([].Base, "Reshape", {Get: ArrReshape})
DefProp([].Base, "Reverse", {Get: ArrReverse})
DefProp([].Base, "SetItem", {Get: SetArrItem})
if !HasProp([], "Sort")
DefProp([].Base, "Sort", {Get: ArrSort})
DefProp([].Base, "Shape", {Get: GetArrShape})
DefProp([].Base, "Standardization", {Get: ArrStandardization})
DefProp([].Base, "Swap", {Get: ArrSwap})
;Redefine Map
; Redefine Object
DefProp({}.Base, "Map", {Get: Object2Map})
; Redefine String
DefProp("".Base, "Array", {Get: StrSplit})
; Related Func
ArrAppend(this)
{
Return ArrAppend2
}
ArrAppend2(this, Content*)
{
this.Push(Content*)
}
ArrCount(this)
{
Return ArrCount2
}
ArrCount2(this, Obj)
{
Return_Count := 0
For i in this
{
if !ListCmp(i, Obj)
Return_Count++
}
Return Return_Count
}
ArrExtend(this)
{
Return ArrExtend2
}
ArrExtend2(this, Extend_Lst*)
{
Loop Extend_Lst.Length
{
if !Extend_Lst[A_Index].Dims
this.Push(Extend_Lst[A_Index])
else
{
For i in Extend_Lst[A_Index]
this.Push(i)
}
}
Return this
}
ArrIndex(this)
{
Return ArrIndex2
}
ArrIndex2(this, Obj)
{
Index := -1
For i in this
{
if !ListCmp(i, Obj)
{
Index := A_Index
Break
}
}
Return Index
}
ArrInsert(this)
{
Return ArrInsert2
}
ArrInsert2(this, Index, Obj*)
{
this.InsertAt(Index, Obj*)
Return this
}
ArrIReshape(this)
{
Return ArrIReshape2
}
ArrIReshape2(this, Shape)
{
this.Ravel()
Return this.Reshape(Shape)
}
ArrRavel(this)
{
Return ArrRavel2
}
ArrRavel2(this)
{
if !this.MaxDim
Return this
Tmp := []
For i in this
{
if !i.Dims
Tmp.Push(i)
else
Tmp.Extend(ArrRavel2(i))
}
this.Length := 0
For j in Tmp
this.Push(j)
Return this
}
ArrRemove(this)
{
Return ArrRemove2
}
ArrRemove2(this, Obj*)
{
Loop Obj.Length
{
Index := this.Index(Object[A_Index])
if Index != -1
this.Pop(Index)
}
Return this
}
ArrReshape(this)
{
Return ArrReshape2
}
ArrReshape2(this, Shape)
{
OldShape := this.Shape
TmpShape := Shape.Clone()
if OldShape.Product !== Shape.Product
Return this
if Shape.Length == 1
Return this.Ravel()
this.Ravel()
Tmpthis := this.Clone()
Tmp := []
LoopTimes := TmpShape.RemoveAt(1)
Loop LoopTimes
{
Tmp2 := []
Loop TmpShape.Product
Tmp2.Push(Tmpthis.RemoveAt(1))
Tmp.Push(ArrReshape2(Tmp2, TmpShape))
}
this.Length := 0
For j in Tmp
this.Push(j)
Return this
}
ArrReverse(this)
{
Return ArrReverse2
}
ArrReverse2(this)
{
Loop this.Length // 2
this.Swap(A_Index, this.Length - A_Index + 1)
Return this
}
ArrSort(this)
{
Return ArrSort2
}
ArrSort2(this, cmp := "", key := "", reverse := False)
{
if (key is String) && InStr(key, "reverse")
reverse := Trim(StrSplit(key, "=")[2])
if (cmp is String) && InStr(cmp, "key")
key := %Trim(StrSplit(cmp, "=")[2])%
if (cmp is String) && InStr(cmp, "reverse")
reverse := Trim(StrSplit(cmp, "=")[2])
if !(cmp is Func)
cmp := ListCmp
if !key
{
Loop this.Length
{
Index := A_Index
Loop this.Length - Index
{
if cmp(this[Index], this[A_Index + Index]) > 0
this.Swap(Index, A_Index + Index)
}
}
}
else
{
Loop this.Length
{
Index := A_Index
Loop this.Length - Index
{
if key(this[Index]) > key(this[A_Index + Index])
this.Swap(Index, A_Index + Index)
}
}
}
if reverse
this.Reverse()
Return this
}
ArrStandardization(this)
{
Return ArrStandardization2
}
ArrStandardization2(this)
{
if this.Dims == 1
Return this
Shape := []
Loop this.Dims
Shape.Push(this.MaxLength(A_Index))
Ret := ArrStandardShape(this, Shape)
For i in Ret
this[A_Index] := i
Return this
}
ArrStandardShape(this, Shape)
{
if Shape.Length == 1
{
Tmp := this.Dims ? this : [this]
Loop Shape[1] - Tmp.Length
Tmp.Push(0)
Return Tmp
}
Tmp := this.Dims ? this : [this]
Loop Shape[1] - Tmp.Length
Tmp.Push(0)
TmpShape := Shape.Clone()
TmpShape.RemoveAt(1)
For i in Tmp
Tmp[A_Index] := ArrStandardShape(i, TmpShape)
Return Tmp
}
ArrSwap(this)
{
Return ArrSwap2
}
ArrSwap2(this, Index1, Index2)
{
if Index1 > this.Length || Index2 > this.Length || Index1 == Index2
Return this
Temp := this[Index1]
this[Index1] := this[Index2]
this[Index2] := Temp
Return this
}
GetArrDims(this)
{
Tmp := []
For i in this
Tmp.Push(HasProp(i, "Dims") ? i.Dims : 0)
Return Max(Tmp*) + 1
}
GetArrItem(this)
{
Return GetArrItem2
}
GetArrItem2(this, Pos*)
{
Ret := this.Clone()
Loop Pos.Length
Ret := Ret[Pos[A_Index]]
Return Ret
}
GetArrMax(this)
{
Tmp := this.Clone()
Return this.Length ? Tmp.Sort()[-1] : ""
}
GetArrMaxDim(this)
{
Return this[GetArrMaxDimIndex(this)].Dims
}
GetArrMaxLength(this)
{
Return GetArrMaxLength2
}
GetArrMaxLength2(this, Dim := 1)
{
if !this.Dims || Dim > this.Dims
Return 1
if Dim == 1
Return this.Length
MaxLength := 1
Dim--
For i in this
{
if GetArrMaxLength2(i, Dim) > MaxLength
MaxLength := GetArrMaxLength2(i, Dim)
}
Return MaxLength
}
GetArrMaxDimIndex(this)
{
MaxDim := 0
MaxDimIndex := 1
For i in this
{
if i.Dims > MaxDim
{
MaxDim := i.Dims
MaxDimIndex := A_Index
}
}
Return MaxDimIndex
}
GetArrMin(this)
{
Tmp := this.Clone()
Return this.Length ? Tmp.Sort()[1] : ""
}
GetArrProduct(this)
{
Ret := 1
For i in this
{
if Ret == 0
Return Ret
if i.Dims
Ret *= GetArrProduct(i)
else
{
Try
Ret *= i
}
}
Return Ret
}
GetArrShape(this)
{
this.Standardization()
Tmp := this.Clone()
Shape := []
While Tmp.MaxDim
{
Shape.Push(Tmp.Length)
Tmp := Tmp[Tmp.MaxDimIndex]
}
Shape.Push(Tmp.Length)
Return Shape
}
ListCmp(Lst1, Lst2)
{
Lst1 := Print.ToString(Lst1)
Lst2 := Print.ToString(Lst2)
if StrCompare(Lst1, Lst2) < 0
Return -1
else if StrCompare(Lst1, Lst2) > 0
Return 1
else
Return 0
}
Object2Map(this)
{
Tmp := Map()
For Key, Value in this.OwnProps()
Tmp[Key] := Value
Return Tmp
}
SetArrItem(this)
{
Return SetArrItem2
}
SetArrItem2(this, Pos*)
{
Ret := [this[Pos[1]]]
Loop Pos.Length - 3
Ret.Push(Ret[A_Index][Pos[A_Index + 1]])
Ret[-1][Pos[-2]] := Pos[-1]
Return this
}
使用说明:
依赖库Print用于调试以及使用Print.ToString函数。
Print源码
Class Print
{
Static _gui := "", hwnd := 0, ctlHwnd := 0
Static StartMakingGui := 0, locked := 1
Static WinName := "Print Window"
Static FloatPos := 8
__New(Content, TimeStamp := true)
{
Print.Msg(Content, TimeStamp)
}
Static Msg(Content, TimeStamp := true)
{
this.makeGui()
Content := Print.ToString(Content)
If (TimeStamp) ; append timestamp + str
Content := "[" A_Hour ":" A_Min ":" A_Sec "] " Content "`r`n"
If (this.hwnd)
{
Lst_Content := StrSplit(Content, "`n")
Loop Lst_Content.Length
{
this.AppendTxt(this.ctlHwnd, StrPtr(Lst_Content[A_Index]))
this._gui["EditBox"].Value .= "`n"
}
}
}
Static makeGui()
{
If (WinExist("ahk_id " this.hwnd))
return
If (this.hwnd Or this.StartMakingGui) ; skip making the GUI
return
this.StartMakingGui := 1
guiClose := ObjBindMethod(this,"gClose")
this.guiClose := guiClose
guiSize := ObjBindMethod(this,"gSize")
this.guiSize := guiSize
ctlEvent := ObjBindMethod(this,"event")
this.ctlEvent := ctlEvent
ArkDebugObj := Gui("+Resize +AlwaysOnTop", this.WinName)
ArkDebugObj.OnEvent("close", this.guiClose)
ArkDebugObj.OnEvent("size", this.guiSize)
ArkDebugObj.SetFont("s11","Courier New")
ctl := ArkDebugObj.Add("Button","vCopy x5 y5 Section","Copy to Clipboard").OnEvent("Click",ctlEvent)
ctl := ArkDebugObj.Add("Button","vClear yp x+5","Clear Window").OnEvent("Click",ctlEvent)
ctl := ArkDebugObj.Add("Edit","vEditBox xs y+0 w700 h500 Multi ReadOnly")
this.ctlHwnd := ctl.hwnd, ctl := ""
ArkDebugObj.Show("NA NoActivate")
this.locked := 0
this.hwnd := ArkDebugObj.hwnd
this.locked := 1
this._gui := ArkDebugObj
}
Static gClose(g)
{
this._gui.Destroy()
this.hwnd := 0, this.ctlHwnd := 0
this.StartMakingGui := 0
}
Static gSize(g, MinMax, Width, Height)
{
; msgbox "in size"
x := "", y := "", w := "", h := "", ctl := ""
w := Width - 10, h := Height - 10 - 40
ctl := g["EditBox"]
ctl.GetPos(&x,&y)
ctl.Move(x,y,w,h)
}
Static AppendTxt(hEdit, ptrText, loc:="bottom")
{
charLen := SendMessage(0x000E, 0, 0, , "ahk_id " hEdit) ;WM_GETTEXTLENGTH
If (loc = "bottom")
SendMessage 0x00B1, charLen, charLen, , "ahk_id " hEdit ;EM_SETSEL
Else If (loc = "top")
SendMessage 0x00B1, 0, 0,, "ahk_id " hEdit
SendMessage 0x00C2, False, ptrText, , "ahk_id " hEdit ;EM_REPLACESEL
}
Static event(ctl,info)
{
If (ctl.Name = "Copy")
A_Clipboard := ctl.gui["EditBox"].Value
Else If (ctl.Name = "Clear")
ctl.gui["EditBox"].Value := ""
}
Static ToString(Text)
{
if Type(Text) == "Array"
{
if Text.Length < 1
Text.InsertAt(1, "")
String_Plus := ""
String_Text := "[" . Print.ToString(Text[1])
Loop Text.Length - 1
String_Plus .= "," . Print.ToString(Text[A_Index + 1])
String_Text .= String_Plus
String_Text .= "]"
Return String_Text
}
else if Type(Text) == "List"
{
if Text.Length < 1
Text.InsertAt(1, "")
String_Plus := ""
String_Text := "[" . Print.ToString(Text[0])
Loop Text.Length - 1
String_Plus .= "," . Print.ToString(Text[A_Index])
String_Text .= String_Plus
String_Text .= "]"
Return String_Text
}
else if Type(Text) == "ComObjArray"
{
if Text.MaxIndex() < 0
{
Text := ComObjArray(VT_VARIANT:=12, 1)
Text[0] := ""
}
String_Plus := ""
String_Text := "[" . Print.ToString(Text[0])
Loop Text.MaxIndex()
String_Plus .= "," . Print.ToString(Text[A_Index])
String_Text .= String_Plus
String_Text .= "]"
Return String_Text
}
else if Type(Text) == "Numpy.NDArray" || Type(Text) == "Numahk.NDArray"
{
if Text.array.Length < 1
Text.array.InsertAt(1, "")
String_Plus := ""
String_Text := "[" . Print.ToString(Text.array[0])
Loop Text.array.Length - 1
String_Plus .= "," . Print.ToString(Text.array[A_Index])
String_Text .= String_Plus
String_Text .= "]"
Return String_Text
}
else if Type(Text) == "Set"
Return "Set(" Print.ToString(Text.list) ")"
else if Type(Text) == "Map" || Type(Text) == "Dict"
{
String_Text := "{"
For i, Value in Text
String_Text .= Print.ToString(i) . ":" . Print.ToString(Value) . ","
if SubStr(String_Text, -1) !== "{"
String_Text := SubStr(String_Text, 1, StrLen(String_Text) - 1)
String_Text .= "}"
Return String_Text
}
else if Type(Text) == "Pandas.DataFrame"
{
String_Text := "`t"
For i in Text.Columns
String_Text .= Print.ToString(i) "`t"
String_Text := SubStr(String_Text, 1, StrLen(String_Text) - 1)
String_Text .= "`n"
Loop Text.Index.Length
{
index := A_Index - 1
String_Text .= Print.ToString(Text.Index[index]) "`t"
Loop Text.Data.array.Length
String_Text .= Print.ToString(Text.Data.array[A_Index - 1][index]) "`t"
String_Text := SubStr(String_Text, 1, StrLen(String_Text) - 1)
String_Text .= "`n"
}
String_Text := SubStr(String_Text, 1, StrLen(String_Text) - 1)
Return String_Text
}
else if Type(Text) == "Integer" || Type(Text) == "String"
Return String(Text)
else if Type(Text) == "Float"
Return Round(Text, this.FloatPos)
else if Type(Text) == "Object"
{
String_Text := "{"
For i, Value in Text.OwnProps()
String_Text .= Print.ToString(i) . ":" . Print.ToString(Value) . ","
if SubStr(String_Text, -1) !== "{"
String_Text := SubStr(String_Text, 1, StrLen(String_Text) - 1)
String_Text .= "}"
Return String_Text
}
else if Type(Text) == "ListNode"
{
String_Text := "{val:"
String_Text .= Print.ToString(Text.val)
String_Text .= "}"
if Text.next
{
String_Text .= "->"
String_Text .= Print.ToString(Text.next)
}
Return String_Text
}
else if Type(Text) == "Cv_Mat_Object"
{
String_Text := "Channels: " Text.Channels
String_Text .= "`nData: " Text.Data
String_Text .= "`nDepth: " Text.Depth
String_Text .= "`nShape: " Print.ToString([Text.Rows, Text.Cols, Text.Channels])
String_Text .= "`nSize: " Text.Size
String_Text .= "`nStep1: " Text.Step1
String_Text .= "`nTotal: " Text.Total
String_Text .= "`nType: " Text.Type
String_Text .= "`nCols: " Text.MAT.Cols
String_Text .= "`nDims: " Text.MAT.Dims
String_Text .= "`nRows: " Text.MAT.Rows
Return String_Text
}
else if Type(Text) == "CV2.MAT"
{
Return Print.ToString(Text.MAT)
}
else if Type(Text) == "Func"
{
String_Text := "Name: " Text.Name
String_Text .= "`nIsBuiltIn: " Text.IsBuiltIn
String_Text .= "`nIsVariadic: " Text.IsVariadic
String_Text .= "`nMinParams: " Text.MinParams
String_Text .= "`nMaxParams: " Text.MaxParams
Return String_Text
}
else if Type(Text) == "Class"
{
String_Text := ""
For item, value in Text.Prototype.OwnProps()
String_Text .= item ": " value "`n"
Return SubStr(String_Text, 1, StrLen(String_Text) - 1)
}
else if Type(Text) == "Gui"
{
String_Text := "BackColor: " Text.BackColor
String_Text .= "`nFocusedCtrl: " Text.FocusedCtrl
String_Text .= "`nHwnd: " Text.Hwnd
String_Text .= "`nMarginX: " Text.MarginX
String_Text .= "`nMarginY: " Text.MarginY
String_Text .= "`nMenuBar: " Text.MenuBar
String_Text .= "`nName: " Text.Name
String_Text .= "`nTitle: " Text.Title
String_Text .= "`nItem: `n{`n"
For Hwnd, GuiCtrlObj in Text
{
String_Text .= " Control #" A_Index "[Hwnd: " Hwnd ",ClassNN: " GuiCtrlObj.ClassNN "]`n"
}
String_Text .= "}"
Return String_Text
}
else
Return "#Type: " Type(Text) "#"
}
}