通过路径写入动态多维 table
Writing to Dynamic Multidimensional table via path
从
开始
我的数据结构像
local data = {
[1] = {
[1] = { "stuff" },
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
}
}
我在上面添加了以下元数据table
__index = function(t, k)
for i,v in ipairs(k) do
if not t then error("attempt to index nil") end
t = rawget(t, v)
end
return t
end
})
print(data[{2,3,1}]
这对于获取数据非常有用,但是当我尝试设置数据时,它反而会创建一个新的 table。例如data[{2,3,1}] = "Updated Stuff"
将数据变成
[1] = {
[1] = { "stuff" }
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
},
["table: 000001A7E014F570"] = "Updated Stuff"
}
虽然如果我然后调用 print(data[{2,3,1}]
我得到正确的值但是如果我然后尝试使用 ipairs 递归循环遍历 table 我得到原始值并且忽略额外的值。我知道从 Lua 的意义上来说这应该是可能的,但就是只见树木不见森林。
我想我正在寻找 Lua 相当于 lodash 的 _.set(table, "path.to.key", value)
print(data[{2,3,1}])
索引数据并因此调用您的 __index
元方法,然后 returns 字符串 "deeper stuff"
data[{2,3,1}] = "updated stuff"
是一个赋值索引操作。它会调用 __newindex
,而不是 __index
.
由于您没有 __newindex
,您只是使用 table {2,3,1}
作为 table 键进行常规分配。
如果您想使用 table 的内容作为索引 data[2][3][1]
.
的键,您必须实施 __newindex
我不确定你为什么更喜欢 data[{2,3,1}]
而不是 data[2][3][1]
。你在增加不必要的混乱。在 table 中提供 table 键会很方便的少数情况可以使用一个同时接受 table 和键列表的简单函数来解决。但这只是我个人的意见。
我刚刚向您展示了我最后一个答案的可能性。这并不意味着这样做是个好主意 :) 抱歉,如果不清楚。
您可以简单地使用两个函数:
updateDeep(t, newVal, ...)
和 getDeep(t, ...)
可以类似于 __index 元方法实现。将 k
替换为 {...}
您还应该实现 __newindex
元方法
local data = {
[1] = {
[1] = { "stuff" },
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
}
}
setmetatable(data, {
__index = function(t, k)
for i, k in ipairs(k) do
if t == nil then return nil end
if type(t) ~= "table" then error("Unexpected subtable", 2) end
t = rawget(t, k)
end
return t
end,
__newindex = function(t, k, v)
local last_k
for i, k in ipairs(k) do
k, last_k = last_k, k
if k ~= nil then
local parent_t = t
t = rawget(parent_t, k)
if t == nil then
t = {}
rawset(parent_t, k, t)
end
if type(t) ~= "table" then error("Unexpected subtable", 2) end
end
end
rawset(t, last_k, v)
end
})
print(data[{2,3,1}])
data[{2,3,1}] = "updated stuff #1"
print(data[{2,3,1}])
data[{3,1,2}] = "updated stuff #2"
print(data[{3,1,2}])
从
我的数据结构像
local data = {
[1] = {
[1] = { "stuff" },
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
}
}
我在上面添加了以下元数据table
__index = function(t, k)
for i,v in ipairs(k) do
if not t then error("attempt to index nil") end
t = rawget(t, v)
end
return t
end
})
print(data[{2,3,1}]
这对于获取数据非常有用,但是当我尝试设置数据时,它反而会创建一个新的 table。例如data[{2,3,1}] = "Updated Stuff"
将数据变成
[1] = {
[1] = { "stuff" }
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
},
["table: 000001A7E014F570"] = "Updated Stuff"
}
虽然如果我然后调用 print(data[{2,3,1}]
我得到正确的值但是如果我然后尝试使用 ipairs 递归循环遍历 table 我得到原始值并且忽略额外的值。我知道从 Lua 的意义上来说这应该是可能的,但就是只见树木不见森林。
我想我正在寻找 Lua 相当于 lodash 的 _.set(table, "path.to.key", value)
print(data[{2,3,1}])
索引数据并因此调用您的 __index
元方法,然后 returns 字符串 "deeper stuff"
data[{2,3,1}] = "updated stuff"
是一个赋值索引操作。它会调用 __newindex
,而不是 __index
.
由于您没有 __newindex
,您只是使用 table {2,3,1}
作为 table 键进行常规分配。
如果您想使用 table 的内容作为索引 data[2][3][1]
.
__newindex
我不确定你为什么更喜欢 data[{2,3,1}]
而不是 data[2][3][1]
。你在增加不必要的混乱。在 table 中提供 table 键会很方便的少数情况可以使用一个同时接受 table 和键列表的简单函数来解决。但这只是我个人的意见。
我刚刚向您展示了我最后一个答案的可能性。这并不意味着这样做是个好主意 :) 抱歉,如果不清楚。
您可以简单地使用两个函数:
updateDeep(t, newVal, ...)
和 getDeep(t, ...)
可以类似于 __index 元方法实现。将 k
替换为 {...}
您还应该实现 __newindex
元方法
local data = {
[1] = {
[1] = { "stuff" },
},
[2] = {
[1] = { "stuff" },
[2] = { "more stuff" },
[3] = {
[1] = "deeper stuff"
}
}
}
setmetatable(data, {
__index = function(t, k)
for i, k in ipairs(k) do
if t == nil then return nil end
if type(t) ~= "table" then error("Unexpected subtable", 2) end
t = rawget(t, k)
end
return t
end,
__newindex = function(t, k, v)
local last_k
for i, k in ipairs(k) do
k, last_k = last_k, k
if k ~= nil then
local parent_t = t
t = rawget(parent_t, k)
if t == nil then
t = {}
rawset(parent_t, k, t)
end
if type(t) ~= "table" then error("Unexpected subtable", 2) end
end
end
rawset(t, last_k, v)
end
})
print(data[{2,3,1}])
data[{2,3,1}] = "updated stuff #1"
print(data[{2,3,1}])
data[{3,1,2}] = "updated stuff #2"
print(data[{3,1,2}])