[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Extract a list of keys from table
- From: "Alexander Gladysh" <agladysh@...>
- Date: Thu, 17 Jul 2008 23:26:46 +0400
Hi, list!
I need the function which would work as follows:
print(
extract_keys(
{ a = 1, b = 2, c = 3 },
"a", "b", "xxx", "c", "yyy"
)
)
--> 1 2 nil 3 nil
It is quite simple to write one in C API:
static int Lextract_keys(lua_State * L) {
int nargs = lua_gettop(L);
int i = 2;
luaL_checktype(L, 1, LUA_TTABLE);
for (i = 2; i <= nargs; ++i) {
lua_pushvalue(L, i);
lua_gettable(L, 1);
}
return nargs - 1;
}
However, I'd like to have one in plain Lua. Naïve version follows:
function extract_keys(t, ...)
local results = {}
local nargs = select("#", ...)
for i = 1, nargs do
results[i] = t[select(i, ...)]
end
return unpack(results, 1, nargs) -- Explicitly specifying range
to handle holes in results array
end
It is not quite good enough because it does create an extra table. Is
there a better way to implement it except to generate code as follows?
do
local function generate_extractor(n)
assert(type(n) == "number")
local a, r = {}, {}
for i = 1, n do
a[i], r[i] = 'a'..i, 't[a'..i..']'
end
return assert(
loadstring(
[[return function(t,]]..table.concat(a,
",")..[[)return ]]..table.concat(r, ",").."end",
"extract_keys_"..n
)
)()
end
local extractors = setmetatable(
{
[0] = function(t) end;
[1] = function(t, a1) return t[a1] end;
[2] = function(t, a1, a2) return t[a1], t[a2] end;
[3] = function(t, a1, a2, a3) return t[a1], t[a2], t[a3] end;
[4] = function(t, a1, a2, a3, a4) return t[a1], t[a2],
t[a3], t[a4] end;
[5] = function(t, a1, a2, a3, a4, a5) return t[a1], t[a2],
t[a3], t[a4], t[a5] end;
},
{
__index = function(t, k)
local v = generate_extractor(k)
rawset(t, k, v)
return v
end
}
)
function extract_keys(t, ...)
return extractors[select("#", ...)](t, ...)
end
end
Assuming that we're extremely rarely need to use that __index stub,
and we always can add more hand-written default entries.
TIA,
Alexander.