mirror of
https://github.com/appgurueu/modlib.git
synced 2024-08-19 04:44:11 +02:00
Add trie
This commit is contained in:
parent
90bb055c6f
commit
cc7a22ea76
3
init.lua
3
init.lua
@ -67,7 +67,8 @@ local components = {
|
|||||||
table = {},
|
table = {},
|
||||||
text = {string = "local"},
|
text = {string = "local"},
|
||||||
threading = {},
|
threading = {},
|
||||||
vector = {}
|
vector = {},
|
||||||
|
trie = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
modlib = {}
|
modlib = {}
|
||||||
|
121
trie.lua
Normal file
121
trie.lua
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
local trie = getfenv(1)
|
||||||
|
|
||||||
|
function new(table) return setmetatable(table or {}, trie) end
|
||||||
|
|
||||||
|
function insert(self, word, value, overwrite)
|
||||||
|
for i = 1, word:len() do
|
||||||
|
local char = word:sub(i, i)
|
||||||
|
self[char] = self[char] or {}
|
||||||
|
self = self[char]
|
||||||
|
end
|
||||||
|
local previous_value = self.value
|
||||||
|
if not previous_value or overwrite then self.value = value or true end
|
||||||
|
return previous_value
|
||||||
|
end
|
||||||
|
|
||||||
|
function remove(self, word)
|
||||||
|
local branch, character = self, word:sub(1, 1)
|
||||||
|
for i = 1, word:len() - 1 do
|
||||||
|
local char = word:sub(i, i)
|
||||||
|
if not self[char] then return end
|
||||||
|
if self[char].value or next(self, next(self)) then
|
||||||
|
branch = self
|
||||||
|
character = char
|
||||||
|
end
|
||||||
|
self = self[char]
|
||||||
|
end
|
||||||
|
local char = word:sub(word:len())
|
||||||
|
if not self[char] then return end
|
||||||
|
self = self[char]
|
||||||
|
local previous_value = self.value
|
||||||
|
self.value = nil
|
||||||
|
if branch and not next(self) then branch[character] = nil end
|
||||||
|
return previous_value
|
||||||
|
end
|
||||||
|
|
||||||
|
--> value if found
|
||||||
|
--> nil else
|
||||||
|
function get(self, word)
|
||||||
|
for i = 1, word:len() do
|
||||||
|
local char = word:sub(i, i)
|
||||||
|
self = self[char]
|
||||||
|
if not self then return end
|
||||||
|
end
|
||||||
|
return self.value
|
||||||
|
end
|
||||||
|
|
||||||
|
function suggestion(self, remainder)
|
||||||
|
local until_now = {}
|
||||||
|
local subtries = { [self] = until_now }
|
||||||
|
local suggestion, value
|
||||||
|
while next(subtries) do
|
||||||
|
local new_subtries = {}
|
||||||
|
local leaves = {}
|
||||||
|
for trie, word in pairs(subtries) do
|
||||||
|
if trie.value then table.insert(leaves, { word = word, value = trie.value }) end
|
||||||
|
end
|
||||||
|
if #leaves > 0 then
|
||||||
|
if remainder then
|
||||||
|
local best_leaves = {}
|
||||||
|
local best_score = 0
|
||||||
|
for _, leaf in pairs(leaves) do
|
||||||
|
local score = 0
|
||||||
|
for i = 1, math.min(#leaf.word, string.len(remainder)) do
|
||||||
|
-- calculate intersection
|
||||||
|
if remainder:sub(i, i) == leaf.word[i] then score = score + 1 end
|
||||||
|
end
|
||||||
|
if score == best_score then table.insert(best_leaves, leaf)
|
||||||
|
elseif score > best_score then best_leaves = { leaf } end
|
||||||
|
end
|
||||||
|
leaves = best_leaves
|
||||||
|
end
|
||||||
|
-- TODO select best instead of random
|
||||||
|
local leaf = leaves[math.random(1, #leaves)]
|
||||||
|
suggestion, value = table.concat(leaf.word), leaf.value
|
||||||
|
break
|
||||||
|
end
|
||||||
|
for trie, word in pairs(subtries) do
|
||||||
|
for char, subtrie in pairs(trie) do
|
||||||
|
local word = { unpack(word) }
|
||||||
|
table.insert(word, char)
|
||||||
|
new_subtries[subtrie] = word
|
||||||
|
end
|
||||||
|
end
|
||||||
|
subtries = new_subtries
|
||||||
|
end
|
||||||
|
return suggestion, value
|
||||||
|
end
|
||||||
|
|
||||||
|
--> value if found
|
||||||
|
--> nil, suggestion, value of suggestion else
|
||||||
|
function search(self, word)
|
||||||
|
for i = 1, word:len() do
|
||||||
|
local char = word:sub(i, i)
|
||||||
|
if not self[char] then
|
||||||
|
local until_now = word:sub(1, i - 1)
|
||||||
|
local suggestion, value = suggestion(self, word:sub(i))
|
||||||
|
return nil, until_now .. suggestion, value
|
||||||
|
end
|
||||||
|
self = self[char]
|
||||||
|
end
|
||||||
|
local value = self.value
|
||||||
|
if value then return value end
|
||||||
|
local until_now = word
|
||||||
|
local suggestion, value = suggestion(self)
|
||||||
|
return nil, until_now .. suggestion, value
|
||||||
|
end
|
||||||
|
|
||||||
|
function find_longest(self, query, query_offset)
|
||||||
|
local leaf_pos = query_offset
|
||||||
|
local last_leaf
|
||||||
|
for i = query_offset, query:len() do
|
||||||
|
local char = query:sub(i, i)
|
||||||
|
self = self[char]
|
||||||
|
if not self then break
|
||||||
|
elseif self.value then
|
||||||
|
last_leaf = self.value
|
||||||
|
leaf_pos = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return last_leaf, leaf_pos
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user