Lua实现有序map容器(类似:std::map)
·
-- 有序映射类,支持自定义比较器
-- 内部使用哈希表 (_data) 存储键值对,数组 (_keys) 维护有序的键列表
local OrderedMap = {}
OrderedMap.__index = OrderedMap
-- 创建新映射
-- @param comparator 比较器,可以是:
-- - 字符串 "asc" 或 "<" 表示升序(默认)
-- - 字符串 "desc" 或 ">" 表示降序
-- - 函数 cmp(a, b) 返回 true 表示 a 应该排在 b 前面
function OrderedMap.new(comparator)
-- 创建元表指向自身,使所有实例共享方法
local self = setmetatable({}, OrderedMap)
self._data = {} -- 键 -> 值的哈希表
self._keys = {} -- 有序的键列表
self._cmp = nil -- 比较函数
-- 根据参数初始化比较器
if comparator == nil or comparator == "asc" or comparator == "<" then
self._cmp = function(a, b) return a < b end -- 默认升序
elseif comparator == "desc" or comparator == ">" then
self._cmp = function(a, b) return a > b end -- 降序
elseif type(comparator) == "function" then
self._cmp = comparator -- 自定义函数
else
error("comparator must be a function, 'asc', 'desc', '<', or '>'")
end
return self
end
-- 内部方法:二分查找键应插入的位置(保持顺序)
-- 返回插入位置的索引(第一个使得 cmp(key, _keys[i]) 为假的索引)
function OrderedMap:_findInsertPos(key)
local keys = self._keys -- 缓存局部变量,提高访问速度
local cmp = self._cmp
local low, high = 1, #keys
while low <= high do
local mid = math.floor((low + high) / 2)
-- 若 key 应排在 keys[mid] 前面,则继续在前半部分查找
if cmp(key, keys[mid]) then
high = mid - 1
else
low = mid + 1 -- 否则在后半部分查找(包括相等的情况)
end
end
return low -- 返回应插入的位置
end
-- 插入或更新键值对
-- 注意:不允许存储 nil 值,若传入 nil 则视为删除该键
function OrderedMap:set(key, value)
-- 处理值为 nil 的情况:调用 remove 删除键并返回
if value == nil then
self:remove(key)
return
end
local data = self._data -- 缓存局部变量
local keys = self._keys
-- 如果键已存在,仅更新值,不改变顺序
if data[key] ~= nil then
data[key] = value
return
end
-- 插入新键:先存储值,再找到合适位置插入键
data[key] = value
local pos = self:_findInsertPos(key)
table.insert(keys, pos, key) -- 在 pos 位置插入键,后续元素自动后移
end
-- 获取键对应的值(若键不存在返回 nil)
function OrderedMap:get(key)
return self._data[key]
end
-- 删除键值对
function OrderedMap:remove(key)
local data = self._data
-- 若键不存在,直接返回
if data[key] == nil then return end
data[key] = nil -- 从哈希表中删除值
local keys = self._keys
-- 遍历有序键列表,找到该键并删除
for i, k in ipairs(keys) do
if k == key then
table.remove(keys, i) -- 删除后,后续元素自动前移
return
end
end
end
-- 返回有序键的数组(副本,避免外部修改)
function OrderedMap:keys()
local copy = {}
for i, k in ipairs(self._keys) do
copy[i] = k
end
return copy
end
-- 返回迭代器函数,用于 for 循环按顺序遍历所有键值对
-- 用法:for key, value in map:ipairs() do ... end
function OrderedMap:ipairs()
local keys = self._keys -- 缓存局部变量
local data = self._data
local i = 0
-- 闭包迭代器,每次调用返回下一个键值对
return function()
i = i + 1
local key = keys[i]
if key then
return key, data[key]
end
end
end
-- 返回键值对数量
function OrderedMap:size()
return #self._keys
end
-- 清空所有数据
function OrderedMap:clear()
self._data = {}
self._keys = {}
end
-- 支持 Lua 5.2+ 的 __pairs 元方法,使 pairs(map) 能按顺序迭代
-- 直接复用 ipairs 方法(ipairs 本身返回迭代器)
OrderedMap.__pairs = OrderedMap.ipairs
-- 为兼容性提供别名,建议显式调用 ipairs
OrderedMap.pairs = OrderedMap.ipairs
-- 示例使用(仅当直接运行此文件时执行)
if ... then
-- 升序(默认)
local map = OrderedMap.new() -- 或 "asc"
map:set("b", 2)
map:set("a", 1)
map:set("c", 3)
for k, v in map:ipairs() do
print(k, v) -- 输出 a 1, b 2, c 3
end
-- 降序
local map2 = OrderedMap.new("desc")
map2:set(5, "five")
map2:set(1, "one")
map2:set(3, "three")
for k, v in map2:ipairs() do
print(k, v) -- 输出 5 five, 3 three, 1 one
end
-- 自定义比较器:按字符串长度排序
local map3 = OrderedMap.new(function(a, b) return #a < #b end)
map3:set("apple", "fruit")
map3:set("banana", "fruit")
map3:set("pear", "fruit")
for k, v in map3:ipairs() do
print(k, v) -- 输出 pear fruit, apple fruit, banana fruit (长度升序)
end
end
return OrderedMap
更多推荐

所有评论(0)