lua-users home
lua-l archive

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


On 11.09.2022 1:40, Luiz Henrique de Figueiredo wrote:
We appreciate tested code solutions for problems and enhancements; we
just don't incorporate third-party code verbatim.

So, sure, please, let's see your code.

Maybe it's just me, but since all the commits are done by the author, I assumed that literally everyone else is considered a "third-party".

Anyway, here's my implementation. I'm also attaching a test script, not sure if this mailing list allows attachments though.

//--------

static int tremove (lua_State *L) {
  lua_Integer i;
  lua_Integer size = aux_getn(L, 1, TAB_RW);
  lua_Integer pos = luaL_optinteger(L, 2, size);
  lua_Integer count = luaL_optinteger(L, 3, 1);
  if(count < 0) {  /* if 'count' is negative, convert the call to 'table.remove(t, pos + count + 1, -count)' */
    lua_pop(L, 2);
    lua_pushinteger(L, pos + count + 1);
    lua_pushinteger(L, -count);
    return tremove(L);
  } /* 'count' from now on is strictly positive */
  /* check whether 'pos' is in [1, size + 1] */
  luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
                    "position out of bounds");
  for(i = 0; i < count; i++)  /* push 'count' elements onto the stack starting from 'pos' */
    lua_geti(L, 1, pos + i);
  for (i = pos ; i <= size; i++) {  /* shift the rest */
    lua_geti(L, 1, i + count);
    lua_seti(L, 1, i);  /* t[pos] = t[pos + count] */
  }
  if(pos + count - 1 <= size) {  /* remove the tail (if present) */
    for(i = size - count + 1; i <= size; i++) {
      lua_pushnil(L);
      lua_seti(L, 1, i);
    }
  }
  return count;
}

//--------


On 11.09.2022 2:09, Egor Skriptunoff wrote:
On Sat, Sep 10, 2022 at 8:16 PM Alexander Chernoskutov wrote:
Right know there's no good way to remove `count` elements from a table.


By using table.move(), it is possible to create implementation with O(#t) time complexity:

function table.remove_count (list, pos, count)
   pos = pos or #list
   count = count or 1
   return
      (
         function (...)
            table.move(list, pos + count, #list + count, pos)
            return ...
         end
      )
      (
         table.unpack(list, pos, pos + count - 1)
      )
end

Brilliant solution, really. But I think it only further illustrates my point.
My opinion is that such a trivial operation (removing k elements) should be a bit more accessible to non-professional programmers (those who's job does not include thinking about complexity and functional programming patterns).



--
With regards, Alex Ch


  

function init_t()
    return {1,2,3,4,5,6,7,8,9,10}
end

function assert_t_eq(t1, t2)
    if #t1 ~= #t2 then
        print('assertion failed: ', table.unpack(t1), "(" .. #t1 .. ")", "~=", table.unpack(t2), "(" .. #t2 .. ")")
        error('assertion failed')
    end
    for i = 1, #t1 do
        if t1[i] ~= t2[i] then
            print('assertion failed: ', table.unpack(t1), "(" .. #t1 .. ")", "~=", table.unpack(t2), "(" .. #t2 .. ")")
            error('assertion failed')
        end
    end
end

local t, tail

t = init_t()
tail = {table.remove(t)}
assert_t_eq(t, {1,2,3,4,5,6,7,8,9})
assert_t_eq(tail, {10})

t = init_t()
tail = {table.remove(t, 1)}
assert_t_eq(t, {2,3,4,5,6,7,8,9,10})
assert_t_eq(tail, {1})

t = init_t()
tail = {table.remove(t, 1, 3)}
assert_t_eq(t, {4,5,6,7,8,9,10})
assert_t_eq(tail, {1,2,3})

t = init_t()
tail = {table.remove(t, #t, -3)}
assert_t_eq(t, {1,2,3,4,5,6,7})
assert_t_eq(tail, {8,9,10})

t = init_t()
tail = {table.remove(t, 4, 3)}
assert_t_eq(t, {1,2,3,7,8,9,10})
assert_t_eq(tail, {4,5,6})

t = init_t()
tail = {table.remove(t, 2, 12)}
assert_t_eq(t, {1})
assert_t_eq(tail, {2,3,4,5,6,7,8,9,10})

t = init_t()
tail = {table.remove(t, 2, 0)}
assert_t_eq(t, init_t())
assert_t_eq(tail, {})

print("test table.remove()", "Ok")