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