kikito的回答是不錯的,但有一些缺陷:
- 如果執行
t[{a=1}] = true
兩次,store
將包含兩個表(內存泄漏的哈希表的壽命)
- 修改值一次你已經存儲它不起作用,你也不能刪除它。嘗試改變它會導致檢索過程中返回您分配給該鍵的任何值。訪問性能爲O(n)(n爲存儲條目的數量,假設lua從表中檢索到的值爲O(1));結合第一點,這個哈希表的性能將在使用
(另請注意,kikito的「等效」功能將導致無限循環,如果任何表具有循環引用。)
如果降級永遠不需要更改/刪除表中的任何信息,那麼kikito的答案就足夠了。否則,元表必須改變,這樣__newindex確保該表不存在:
t = setmetatable({}, {
__newindex = function(tbl, key, value)
for k,v in pairs(store) do
if equivalent(k,key) then
tbl[k] = value
return
end
end
store[key] = value
end,
__index = function(tbl, key)
for k,v in pairs(store) do
if equivalent(k, key) then return v end
end
end
})
正如你所說,一個完全不同的選擇是編寫一個自定義的散列函數。這裏有一個哈希表,可以利用的是:
local function HashTable(Hash, Equals)
--Hash is an optional function that takes in any key and returns a key that lua can use (string or number). If you return false/nil, it will be assumed that you don't know how to hash that value.
-- If Hash is not provided, table-keys should have a GetHash function or a .Hash field
--Equals is an optional function that takes two keys and specify whether they are equal or not. This will be used when the same hash is returned from two keys.
-- If Equals is not provided, items should have a Equals function; items are in this case assumed to not be equal if they are different types.
local items = {} --Dict<hash, Dict<key, value>>
local function GetHash(item)
return Hash and Hash(item) or type(item) == "table" and (item.GetHash and item:GetHash() or item.Hash) or item
end
local function GetEquals(item1, item2)
if Equals then return Equals(item1, item2) end
local t1, t2 = type(item1), type(item2)
if t1 ~= t2 then return false end
if t1 == "table" and item1.Equals then
return item1:Equals(item2)
elseif t2 == "table" and item2.Equals then
return item2:Equals(item1)
end
return false
end
return setmetatable({}, {
__newindex = function(_, key, value)
local hash = GetHash(key)
local dict = items[hash]
if not dict then
if value ~= nil then --Only generate a table if it will be non-empty after assignment
items[hash] = {[key] = value}
end
return
end
for k, v in pairs(dict) do
if GetEquals(key, k) then --Found the entry; update it
dict[k] = value
if value == nil then --check to see if dict is empty
if next(dict) == nil then
items[hash] = nil
end
end
return
end
end
--This is a unique entry
dict[key] = value
end,
__index = function(_, key)
local hash = GetHash(key)
local dict = items[hash]
if not dict then return nil end
for k, v in pairs(dict) do
if GetEquals(key, k) then
return v
end
end
end
})
end
用例:
local h = HashTable(
function(t) return t.a or 0 end, --Hash
function(t1, t2) return t1.a == t2.a end) --Equals
h[{a=1}] = 1
print(h[{a=1}]) -- 1
h[{a=1}] = 2
print(h[{a=1}]) -- 2
print(h[{a=1,b=2}]) -- 2 because Hash/Equals only look at 'a'
當然,你會希望得到更好的散列/的Equals功能。
只要你的密鑰的哈希值很少碰撞,這個類的性能應該是O(1)。
(注:我已經把這個答案,kikito評論的上半部分,但我沒有在這個時候的口碑這樣做。)
感謝您的答覆。我想要這個的原因是爲了NLP任務。我提取了作爲lua表格存儲的短語(短語中的每個標記作爲使用table.insert映射到索引的值),並且我要計算短語的頻率。我知道還有其他方法可以做我想做的事情(例如連接短語並將該連接字符串用作關鍵字),但這需要額外的實施步驟,並且不會太乾淨。我敢肯定,你可以在Java中做我想做的事情,對於lua來說是新手,我試圖看看是否有模擬 – akobre01 2012-02-09 06:28:13
這樣的散列函數很難寫,因爲表遍歷的順序取決於如何它被創建,所以具有相同條目的表可能具有不同的遍歷。 – lhf 2012-02-09 13:19:01
這就是我爲什麼要將密鑰收集到表格中並對其進行排序以確保密鑰順序一致的原因。 – 2012-02-09 14:35:23