lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


function extract_keys( t, ...)
    local keys = {}
    local potential_keys= {...}
    for i,v in ipairs( potential_keys ) do
        table.insert(keys, i, t[v])
    end
    return unpack(keys, 1, #potential_keys)
end

print( extract_keys( { a = 1, b =2, c = 3 }, "a", "b", "xxx", "c", "yyy"))

?

Keith

On Fri, Jul 18, 2008 at 7:26 AM, Alexander Gladysh <agladysh@gmail.com> wrote:
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.