I have an array of strings in AutoHotkey which contains duplicate entries.
nameArray := ["Chris","Joe","Marcy","Chris","Elina","Timothy","Joe"]
I would like to remove any duplicates so that only unique values remain.
trimmedArray := ["Chris","Joe","Marcy","Elina","Timothy"]
Ideally I'm looking for a function similar to Trim() which would return a trimmed array while leaving the original array intact. (i.e. trimmedArray := RemoveDuplicates(nameArray)
)
How do I remove duplicates from my AutoHotkey array?
Leaves the original intact, only loops once, preserves order:
nameArray := ["Chris","Joe","Marcy","Chris","Elina","Timothy","Joe"]
trimmedArray := trimArray(nameArray)
trimArray(arr) { ; Hash O(n)
hash := {}, newArr := []
for e, v in arr
if (!hash.Haskey(v))
hash[(v)] := 1, newArr.push(v)
return newArr
}
An alternative to using the haskey method, would be to check a value in our hash object. This may prove to be more efficient and faster, but I'll leave the testing to you.
trimArray(arr) { ; Hash O(n)
hash := {}, newArr := []
for e, v in arr
if (!hash[v])
hash[(v)] := 1, newArr.push(v)
return newArr
}
Edit: Initially I wasn't going to test, but I got curious as well as tired of waiting on the OP. The results don't surprise me much:
What we are seeing here is the average execution times for 10,000 tests, the lower the number, the faster the task was computed. The clear winner is my script variation without Haskey Method, but only by tiny margin! All in the other methods were doomed, being that they are not linear solutions.
Test Code is here:
setbatchlines -1
tests := {test1:[], test2:[], test3:[], test4:[]}
Loop % 10000 {
nameArray := ["Chris","Joe","Marcy","Chris","Elina","Timothy","Joe"]
QPC(1)
jimU(nameArray)
test1 := QPC(0), QPC(1)
AbdullaNilam(nameArray)
test2 := QPC(0), QPC(1)
ahkcoderVer1(nameArray)
test3 := QPC(0), QPC(1)
ahkcoderVer2(nameArray)
test4 := QPC(0)
tests["test1"].push(test1), tests["test2"].push(test2)
, tests["test3"].push(test3), tests["test4"].push(test4)
}
scripts := ["Jim U ", "Abdulla Nilam "
, "ahkcoder HasKey", "ahkcoder Bool " ]
for e, testNums in tests ; Averages Results
r .= "Test Script " scripts[A_index] "`t:`t" sum(testNums) / 10000 "`n"
msgbox % r
AbdullaNilam(names) {
for i, namearray in names
for j, inner_namearray in names
if (A_Index > i && namearray = inner_namearray)
names.Remove(A_Index)
return names
}
JimU(nameArray) {
hash := {}
for i, name in nameArray
hash[name] := null
trimmedArray := []
for name, dummy in hash
trimmedArray.Insert(name)
return trimmedArray
}
ahkcoderVer1(arr) { ; Hash O(n) - Linear
hash := {}, newArr := []
for e, v in arr
if (!hash.Haskey(v))
hash[(v)] := 1, newArr.push(v)
return newArr
}
ahkcoderVer2(arr) { ; Hash O(n) - Linear
hash := {}, newArr := []
for e, v in arr
if (!hash[v])
hash[(v)] := 1, newArr.push(v)
return newArr
}
sum(arr) {
r := 0
for e, v in arr
r += v
return r
}
QPC(R := 0) ; https://autohotkey.com/boards/viewtopic.php?t=6413
{
static P := 0, F := 0, Q := DllCall("QueryPerformanceFrequency", "Int64P", F)
return ! DllCall("QueryPerformanceCounter", "Int64P", Q) + (R ? (P := Q) / F : (Q - P) / F)
}
Generates an array containing only the unique elements of another array
uniq(nameArray)
{
hash := {}
for i, name in nameArray
hash[name] := null
trimmedArray := []
for name, dummy in hash
trimmedArray.Insert(name)
return trimmedArray
}
This code uses an associative array to eliminate duplicates. Because it uses a keyed lookup, it should perform better on large arrays than using nested loops, which is O(n²)
Test
for i, name in uniq(["Chris","Joe","Marcy","Chris","Elina","Timothy","Joe"])
s := s . ", " . name
MsgBox % substr(s, 3)
Output
Note that the order of the elements in the first array is not preserved
try this
names := ["Chris","Joe","Marcy","Chris","Elina","Timothy","Joe"]
for i, namearray in names
for j, inner_namearray in names
if (A_Index > i && namearray = inner_namearray)
names.Remove(A_Index)
来源:https://stackoverflow.com/questions/46432447/how-do-i-remove-duplicates-from-an-autohotkey-array