Looking for the best way to use a Scripting.Dictionary object for a case insensitive array that maintains key order (I already have a case sensitive version).
CSobj ('case sensitive object'), which I have made a few amendments to, is based on the Scripting.Dictionary object. Unlike standard AHK arrays, it is case sensitive, and a For loop returns keys in the order they were added, it does not autosort.
I would like to make a similar CIobj ('case insensitive object'), that would be almost the same as a standard AHK array but would maintain key order, and not autosort keys. One way of doing this would be to have all the keys stored as lowercase, with the original case (the first time the key was seen) as the initial characters of the value. The get/set functions would wrap up, hide, all of this, you wouldn't know how ugly things were behind the scenes. But I am looking for the best way of doing this. Other ideas might involve a second array.
Some of the uses for this would include (that I already have the code for, but that I would like to potentially perfect CSobj for, or have 'CIobj' for):
- list comparison: items unique to list A / items unique to list B / items present in both
- table lookup: multiple values against a table/ini file
- table lookup: one value against a list (e.g. a spell list)
- list remove duplicates: remove duplicates, maintain order
- list sort: sort list A based on list B, items in both should be in list B's order, the remaining items in list A should be in their original order
- list line frequency: get frequency for each item, maintain order
Notes:
- CSobj is written in function syntax rather than method syntax.
Objects
https://autohotkey.com/docs/Objects.htm
- The code uses 'self' rather than 'this'.
- To use a Scripting.Dictionary object normally and get its key count:
COM Object Reference [AutoHotkey v1.1+] - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/5698 ... ntry357748
- For a normal AHK array to get its key count:
vCount := NumGet(&oArray + 4*A_PtrSize)
- To get the key count for a CSobj object I added in this method: oArray.count().
- Originally, CSobj couldn't get/set the values for keys that were positive/negative integers, I added in "" in 2 places to make this possible.
- The script mentioned here looks promising but uses the old code for COM.ahk before there was native support.
Scripting.Dictionary Object as Associative Array - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/1639 ... ive-array/
The code below shows the case sensitive 'maintain order' CSobj in action, it lists the keys in their original order, and then sorted.
Code: Select all
q::
oArray := CSobj()
vList := "Q,w,E,-2,1,q,W,e,2,-1,Q,1.5"
Loop, Parse, vList, `,
vKey := A_LoopField, oArray[vKey] := ((vNum := oArray[vKey]) = "") ? 1 : vNum+1
;list array (original item order)
vOutput := "key count: " oArray.count() "`r`n`r`nfrequency table:`r`n"
vList2 := ""
For vKey, vValue in oArray
vOutput .= vKey "`t" vValue "`r`n", vList2 .= vKey "`n"
MsgBox % vOutput
;list array (alphabetical order) (assumes no key name contains a LF)
vOutput := "key count: " oArray.count() "`r`n`r`nfrequency table:`r`n"
vList2 := SubStr(vList2, 1, -1)
Sort, vList2, F JEE_SortAsIfLCase
Loop, Parse, vList2, `n
vOutput .= A_LoopField "`t" oArray[A_LoopField] "`r`n"
MsgBox % vOutput
Return
;==================================================
;JEE_SortStableAsIfLCase
JEE_SortAsIfLCase(vTextA, vTextB, vOffset) ;for use with Sort function
{
StringLower, vTextA, vTextA
StringLower, vTextB, vTextB
Return ("" vTextA) > ("" vTextB) ? 1 : ("" vTextA) < ("" vTextB) ? -1 : -vOffset
}
;==================================================
;based on:
;Case sensitive variables possible? - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/61829-case-sensitive-variables-possible/
;and:
;How make Associative array keys case sensitive - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/61840-how-make-associative-array-keys-case-sensitive/
;updated by jeeswg to allow positive/negative integer keys, and a count method added
CSobj() {
static base := object("_NewEnum","__NewEnum", "Next","__Next", "__Set","__Setter", "__Get","__Getter", "__Call","__Caller")
return, object("__sd_obj__", ComObjCreate("Scripting.Dictionary"), "base", base)
}
__Getter(self, key) {
return, self.__sd_obj__.item("" key)
}
__Setter(self, key, value) {
self.__sd_obj__.item("" key) := value
return, false
}
__NewEnum(self) {
return, self
}
__Next(self, ByRef key = "", ByRef val = "") {
static Enum
if not Enum
Enum := self.__sd_obj__._NewEnum
if Not Enum[key], val:=self[key]
return, Enum:=false
return, true
}
__Caller(self, name) {
if (name = "count")
return, self.__sd_obj__.count
}