Lua中多维表的表过滤器
我正在设计一个通用的表过滤器,它可以从给定的表中删除条目,问题是键不是唯一的,并且类型也不同 让我用一个例子更清楚地阐述一下Lua中多维表的表过滤器,lua,lua-table,Lua,Lua Table,我正在设计一个通用的表过滤器,它可以从给定的表中删除条目,问题是键不是唯一的,并且类型也不同 让我用一个例子更清楚地阐述一下 SampleTable = { { key1 = 10, key2 = 'name_1', Str = 'sample_string_1' }, { key1 = 10, key2 = 'name_3', Str = 'sample_string_2' }, { key1 = 11, key2 = 'name_2', Mac = {
SampleTable = {
{ key1 = 10, key2 = 'name_1', Str = 'sample_string_1' },
{ key1 = 10, key2 = 'name_3', Str = 'sample_string_2' },
{ key1 = 11, key2 = 'name_2', Mac = {'ID1', 'ID2', 'ID3'} },
{ key1 = 11, key2 = 'name_2', Mac = {'ID1'} },
{ key1 = 12, key2 = 'name_4', Mac = {'ID2', 'ID3'} }
}
function filter(inputTable, ...)
filterItems = {...}
end
我想传递任意数量的键来筛选此表
local key1 = 11
local Mac = 'ID1'
filter(SampleTable, key1, Mac)
-- Should return -> { key1 = 11, key2 = 'name_2', Mac = 'ID1'},
key1 = 12
Mac = 'ID3'
filter(SampleTable, key1, Mac)
-- Should return -> { key1 = 12, key2 = 'name_4', Mac = ID3'}
key1 = 11
Mac = 'ID2'
filter(SampleTable, key1, Mac)
-- Should return both
-- { key1 = 11, key2 = 'name_2', Mac = ID2'},
-- { key1 = 11, key2 = 'name_5', Mac = ID2'},
key1 = 10
Str = 'sample_string_2'
filter(SampleTable, key1, Str)
-- Should return { key1 = 10, key2 = 'name_3', Str = 'sample_string_2'}
我目前的解决方案是搜索两个表中的每个键、值对
function filter(tIn, tFilter)
local retain = true
local exist = nil
local tOut = tIn
local _findInTable = function (t, k, v)
if(not t[k]) then return true
elseif(t[k] and t[k] == v) then return true
else return false end
end
for i, t in ipairs (tIn) do
for k,v in pairs (tFilter) do
exist = _findInTable(t, k, v)
retain = retain and exist
end
if not retain then tOut[i] = nil end
retain = true
end
return tOut
end
local myTable = filter(SampleTable, {key1 = 11, Mac = 'ID1'})
问题是我无法预见递归会有多大帮助。
当我有下面的示例表时,这段代码可以工作,正如您可以看到的那样,Mac
不是我代码的子表
SampleTable = {
{ key1 = 10, key2 = 'name_1', Str = 'sample_string_1' },
{ key1 = 10, key2 = 'name_3', Str = 'sample_string_2' },
{ key1 = 11, key2 = 'name_2', Mac = 'ID1' }
-- { key1 = 11, key2 = 'name_2', Mac = {'ID1', 'ID2', 'ID3'} },
-- { key1 = 11, key2 = 'name_2', Mac = {'ID1'} },
-- { key1 = 12, key2 = 'name_4', Mac = {'ID2', 'ID3'} }
}
从您的问题来看,不完全清楚您是在处理递归模式(任意深度和分支结构),还是提供的示例就是它的全部(键总是分配给
n
值,模式中没有递归)。在没有更复杂的示例的情况下,我决定为更简单的案例实现此功能
以下是我对您问题的解决方案,包括您的示例:
local sample = {
{ key1 = 10, key2 = 'name_1', Str = 'sample_string_1' },
{ key1 = 10, key2 = 'name_3', Str = 'sample_string_2' },
{ key1 = 11, key2 = 'name_2', Mac = {'ID1', 'ID2', 'ID3'} },
{ key1 = 11, key2 = 'name_2', Mac = {'ID1'} },
{ key1 = 12, key2 = 'name_4', Mac = {'ID2', 'ID3'} }
}
--- Check if a row matches the specified key constraints.
-- @param row The row to check
-- @param key_constraints The key constraints to apply
-- @return A boolean result
local function filter_row(row, key_constraints)
-- Loop through all constraints
for k, v in pairs(key_constraints) do
if v and not row[k] then
-- The row is missing the key entirely,
-- definitely not a match
return false
end
-- Wrap the key and constraint values in arrays,
-- if they're not arrays already (so we can loop through them)
local actual_values = type(row[k]) == "table" and row[k] or {row[k]}
local required_values = type(v) == "table" and v or {v}
-- Loop through the values we *need* to find
for i = 1, #required_values do
local found
-- Loop through the values actually present
for j = 1, #actual_values do
if actual_values[j] == required_values[i] then
-- This object has the required value somewhere in the key,
-- no need to look any farther
found = true
break
end
end
if not found then
return false
end
end
end
return true
end
--- Filter an array, returning entries matching `key_values`.
-- @param input The array to process
-- @param key_values A table of keys mapped to their viable values
-- @return An array of matches
local function filter(input, key_values)
local result = {}
for i = 1, #input do
local row = input[i]
if filter_row(row, key_values) then
result[#result + 1] = row
end
end
return result
end
下面是示例输出,带有一个实用工具deep\u print()
函数:
--- Recursively print out a Lua value.
-- @param value The value to print
-- @param indent Indentation level (defaults to 0)
-- @param no_newline If true, won't print a newline at the end
local function deep_print(value, indent, no_newline)
indent = indent or 0
if type(value) == "table" then
print("{")
for k, v in pairs(value) do
io.write(string.rep(" ", indent + 2) .. "[")
deep_print(k, indent + 2, true)
io.write("] = ")
deep_print(v, indent + 2, true)
print(";")
end
io.write(string.rep(" ", indent) .. "}")
elseif type(value) == "string" then
io.write(("%q"):format(value))
else
io.write(tostring(value))
end
if not no_newline then
print()
end
end
-- The following is a mix of Lua code
-- and the script's output
deep_print(filter(sample, {key1 = 10}))
-- outputs
{
[1] = {
["key1"] = 10;
["key2"] = "name_1";
["Str"] = "sample_string_1";
};
[2] = {
["key1"] = 10;
["key2"] = "name_3";
["Str"] = "sample_string_2";
};
}
deep_print(filter(sample, {key2 = "name_4"}))
-- outputs
{
[1] = {
["key1"] = 12;
["key2"] = "name_4";
["Mac"] = {
[1] = "ID2";
[2] = "ID3";
};
};
}
deep_print(filter(sample, {Mac = {"ID2", "ID3"}}))
-- outputs
{
[1] = {
["key1"] = 11;
["key2"] = "name_2";
["Mac"] = {
[1] = "ID1";
[2] = "ID2";
[3] = "ID3";
};
};
[2] = {
["key1"] = 12;
["key2"] = "name_4";
["Mac"] = {
[1] = "ID2";
[2] = "ID3";
};
};
}
deep_print(filter(sample, {Mac = {"ID2"}}))
-- also outputs
{
[1] = {
["key1"] = 11;
["key2"] = "name_2";
["Mac"] = {
[1] = "ID1";
[2] = "ID2";
[3] = "ID3";
};
};
[2] = {
["key1"] = 12;
["key2"] = "name_4";
["Mac"] = {
[1] = "ID2";
[2] = "ID3";
};
};
}
-- Specifying multiple keys works too:
deep_print(filter(sample, {key2 = "name_3", Str = "sample_string_2"}))
-- outputs
{
[1] = {
["key1"] = 10;
["key2"] = "name_3";
["Str"] = "sample_string_2";
};
}
如您所见,filter\u row()
是非递归的。它仅对行级别的键进行操作。如示例中所示,如果您的模式是平面的,这应该可以工作。如果要筛选的数据实际上更复杂,请提供更多示例
通过首先将值包装到数组(表)中,可以简化键比较的操作。这允许对所有可能的情况使用统一的比较方法(有一点额外的开销)
这是我的第一个答案,如果有任何问题,请编辑/评论。谢谢。您试过按名称查看每个键吗?若你们想以不同的方式处理不同的密钥,那个么这是很有意义的。这是一个普遍的问题,也是对功能的模糊描述。你尝试了什么,什么不起作用?我目前的解决方案,希望能有更好的描述。我一直在寻找一个递归的解决方案,我希望我的问题有一个更递归的解决方案,它可以处理更深层的表。不过,这个解决方案解决了我的问题。