Hello, I’m making a dictionary (name +icon) to be looped through and inserted into a gui. I have a search bar that will update every time the textbox detects input, my only issue is indexing my dictionary with the search parameters. I know I can use string.gmatch but that’s not what im looking for, I want the closest match to the search parameters, how would I do that?
I made a search function based off a Levenshtein distance algorithm a few months ago for someone asking a similar question. I don’t remember how accurate the results were, but I think it might be suitable for your use case?
local function FuzzySearch(ComparisonStrings, SearchString)
local SearchResults = {}
for _,ComparisonString in pairs(ComparisonStrings) do
local ComparisonStringLength = #ComparisonString
local SearchStringLength = #SearchString
if SearchStringLength <= ComparisonStringLength + 5 then
local TempComparisonString = ComparisonString:lower()
local TempSearchString = SearchString:lower()
local Cost
local Rows = ComparisonStringLength + 1
local Columns = SearchStringLength + 1
local Distance = {}
for i = 1, Rows do
Distance[i] = {}
for k = 1, Columns do
Distance[i][k] = 0
end
end
for i = 2, Rows do
for k = 2, Columns do
Distance[i][1] = i
Distance[1][k] = k
end
end
for i = 2, Columns do
for k = 2, Rows do
if TempComparisonString:sub(k - 1, k - 1) == TempSearchString:sub(i - 1, i - 1) then
Cost = 0
else
Cost = 2
end
Distance[k][i] = math.min(
Distance[k - 1][i] + 1,
Distance[k][i - 1] + 1,
Distance[k - 1][i - 1] + Cost
)
end
end
table.insert(SearchResults,
{
Ratio = ((ComparisonStringLength + SearchStringLength) - Distance[Rows][Columns]) / (ComparisonStringLength + SearchStringLength),
Word = ComparisonString
}
)
else
table.insert(SearchResults,
{
Ratio = 0,
Word = ComparisonString
}
)
end
end
table.sort(SearchResults, function(A, B)
return A.Ratio > B.Ratio
end)
return SearchResults -- Returns in the format of { { Ratio, Word }, { Ratio, Word } }. A ratio of 1 means it completely matches and a ratio of 0 means nothing matches at all.
end
local TestStrings = {"Wooden Arrow", "Iron Arrow", "Steel Arrow", "Iron Sword", "Iron Boots", "Iron Pickaxe"}
local SearchString = "Arrow"
local Results = FuzzySearch(TestStrings, SearchString) -- Returns most relevant results first
for _,Result in pairs(Results) do -- Prints "Iron Arrow, Steel Arrow, Wooden Arrow, Iron Sword, Iron Boots, Iron Pickaxe"
print(Result.Word, Result.Ratio)
end