I am looking for a way to pcall a function which has variable arguments in lua5.3.
I am hoping for something like this
function add(...)
local sum=arg + ...
return sum
end
stat,err=pcall(add,...)
thanks
function add(...)
local sum = 0
for _, v in ipairs{...} do
sum = sum + v
end
return sum
end
pcall(add, 1, 2, 3)
--> true 6
or maybe this is closer to what you wanted:
function add(acc, ...)
if not ... then
return acc
else
return add(acc + ..., select(2, ...))
end
end
pcall(add, 1, 2, 3)
--> true 6
Related
Say, I have an array
a = { 1, 2, 10, 15 }
I would like to divide each element by 3 and store the result in a new array. Is there a more efficient / elegant way of doing that than this:
b = { }
for i,x in pairs(a) do
b[i] = x / 3
end
In R, I would simply do b <- a/3. Is there anything like that in lua, or maybe a way of applying a function to each element of a table?
Lua is lightweight, so there is no ready-made functions, but you can create a similar function with metatable.
local mt_vectorization = {
__div = function (dividend, divisor)
local b = {}
for i,x in pairs(dividend) do
b[i] = x / divisor
end
return b
end
}
a = setmetatable({ 1, 2, 10, 15 }, mt_vectorization)
b = a / 3
In addition to the answer by shingo, I found in the meanwhile that writing an R-style mapping function is very easy in lua:
function map(x, f)
local ret = { }
for k, v in pairs(x) do
ret[k] = f(v)
end
return ret
end
This makes some operations easy, for example
a = { 1, 2, 3, 5, 10 }
map(a, function(x) return x * 2 end)
I want do a hookfunction for lua :
For explain i want hook the params and return the params when function called, like this :
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
a = hookfunction(func1, function(...) -- a = old function
local args = { ... }
print("Argument 1 =>", args[1])
print("Argument 2 =>", args[2])
return a(...)
end)
func1(12, 5)
Output :
Argument 1 => 12
Argument 2 => 5
17
There's two different things you can do. You can either create a wrapper just for that function, or you can actually set a debugging hook in the Lua runtime. Here's how you'd create a wrapper:
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
function wrapfunction(a) -- a = old function
return function(...)
local args = { ... }
print("Argument 1 =>", args[1])
print("Argument 2 =>", args[2])
return a(...)
end
end
func1 = wrapfunction(func1)
func1(12, 5)
And here's how you'd set a debugging hook:
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
function hookfunction(event)
if debug.getinfo(2, 'f').func == func1 then
print("Argument 1 =>", select(2, debug.getlocal(2, 1)))
print("Argument 2 =>", select(2, debug.getlocal(2, 2)))
end
end
debug.sethook(hookfunction, 'c')
func1(12, 5)
You can try this
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
oldfunc1 = func1
function func1hook(x, y)
print("Argument x =>", x)
print("Argument y =>", y)
return oldfunc1(x, y)
end
func1 = func1hook
func1(4,4)
I'm not sure it works for C functions but you can try. If you want more universal hookfunction it's also possible.
https://www.lua.org/cgi-bin/demo
I want to be able to map functions that take multiple arguments like
function(a, b) return a+b end
onto a table so that I can write stuff like
answer = varmap(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}
but I am not comfortable with lua varargs and the code samples on wikibooks use table.getn, and when you replace them with # it doesn't work and returns "attempt to preform arithmatic on local 'a' (a nil value)"
One more possibility:
local unpack = table.unpack or unpack
--------------------------------------------------------------------------------
-- Python-like zip() iterator
--------------------------------------------------------------------------------
function zip(...)
local arrays, ans = {...}, {}
local index = 0
return
function()
index = index + 1
for i,t in ipairs(arrays) do
if type(t) == 'function' then ans[i] = t() else ans[i] = t[index] end
if ans[i] == nil then return end
end
return ans
end
end
--------------------------------------------------------------------------------
function map(f,...)
assert(type(f) == 'function','Function expected for 1st arg')
local t = {...}
return coroutine.wrap(
function()
for t in zip(unpack(t)) do
coroutine.yield(f(unpack(t)))
end
end)
end
--------------------------------------------------------------------------------
-- Example use
for item in map(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}) do
print(item)
end
print()
for item in map(function(a) return a*2 end, {1, 7, 3}) do
print(item)
end
local function imap(func, ...) -- imap(func, src_table_1, src_table_2, ...)
local result = {}
local src_tables_arr = {...}
if #src_tables_arr == 1 then
for k, v in ipairs(src_tables_arr[1]) do
result[k] = func(v)
end
else
for k = 1, #src_tables_arr[1] do
result[k] = func(
(table.unpack or unpack)
(
imap(
function(src_t) return src_t[k] end,
src_tables_arr
)
)
)
end
end
return result
end
table.imap = imap
Usage:
local arr = table.imap(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
Perhaps you are looking for something like this:
function varmapn(func, ...)
local args, result = { ... }, {}
for arg_i = 1, #(args[1]) do
local call_args = {}
for arg_list = 1, #args do
table.insert(call_args, args[arg_list][arg_i])
end
table.insert(result, func(table.unpack(call_args)))
end
return result
end
Sample interaction:
> answer = varmapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> print(answer)
table: 0x970eb0
> for i = 1, 3 do print(answer[i]) end
6
11
11
Or, here is a slightly more involved function that is more general. For argument lists it takes arrays, or it takes tables with arbitrary keys:
function mapn(func, ...)
local args, call_args = { ... }, {}
local result = {}
for k in pairs(args[1]) do
call_args[k] = {}
end
for arg_list, v in pairs(args) do
for k in pairs(args[1]) do
table.insert(call_args[k], v[k])
end
end
for k, v in pairs(call_args) do
result[k] = func(table.unpack(v))
end
return result
end
Sample interaction:
> answer = mapn(function (a, b) return a+b end, {x=1, y=7, z=3}, {x=5, y=4, z=8})
> for k,v in pairs(answer) do print(k .. " = " .. v) end
z = 11
y = 11
x = 6
> answer = mapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> for i = 1, 3 do print(answer[i]) end
6
11
11
I'm trying to think of an easy way to make all elements in a table shift up one. It is for a game I am playing, attempting to switch between all targets in a table!
For example, let's say I'm surrounded by three mooks who want to kill me, so I target all of them and they're added into an array like so:
{
"mook1",
"mook2",
"mook3",
}
What I want the function to do is change all indexes to go up one (or the amount I specify), and the last to go to the beginning, so the end result would be:
{
"mook3",
"mook1",
"mook2",
}
I attempted it on my own with a simple function like this:
local function nextIndex(tbl, amount)
local t = {}
for k,v in ipairs(tbl) do
if k < #tbl then
t[k+amount] = v
else
t[1] = v
end
end
return t
end
It works as long as the amount is set to 1. I'm sure there is a much smarter and more efficient way of doing this. Could anyone take a whack at it please?!
You can use a function like this:
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, table.remove( t, #t ) )
end
end
You can see a test run on codepad. or, if you're uncomfortable with nesting of function calls;
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, t[#t] )
table.remove( t, #t )
end
end
would work the same way.
I worked a bit more and figured out how to do it. This is the code:
local function nextIndex(tbl, amount)
local t = {}
local i
for k,v in ipairs(tbl) do
i = k + amount
if i <= #tbl then
t[i] = v
else
t[i-#tbl] = v
end
end
return t
end
Is there an easier way to do it though?
So, the task is to rotate the last rot items to the front.
I added parameter n to allow overriding of the sequence end as determined by #t.
-- uses t[#t+1]...t[#t+rot%#t] as scratch space
local function rotate_mod(t, rot, n)
n = n or #t
rot = rot % n
if rot == 0 then return t end
for i = n, 1, -1 do
t[i + rot] = t[i]
end
for i = 1, rot do
t[i], t[i + n] = t[i + n]
end
return t
end
Or if you want a new array (just ignore parameter r):
local function rotate_new(t, rot, n, r)
n, r = n or #t, {}
rot = rot % n
for i = 1, rot do
r[i] = t[n - rot + i]
end
for i = rot + 1, n do
r[i] = t[i - rot]
end
return r
end
Here's a true "in-place" version. It does not need to temporarily enlarge the table:
local function reverse(t, i, j)
while i < j do
t[i], t[j] = t[j], t[i]
i, j = i+1, j-1
end
end
local function rotate_inplace(t, d, n)
n = n or #t
d = (d or 1) % n
reverse(t, 1, n)
reverse(t, 1, d)
reverse(t, d+1, n)
end
Using Lua (5.1) I would like to fill the table with functions which return several values. Unfortunately, due to Lua specification such function call will only be expanded for the last one.
function get2() return 1, 2 end
local t = { get2(), get2() }
for _,v in pairs(t) do print(v) end
Returns: 1, 1, 2
Is there any way of doing this besides
table = {};
res1, res2 = get2();
table[#table + 1] = res1;
table[#table + 1] = res2
or some other convoluted technique?
No, there is no direct way to do this.
But you can simplify the code with a helper function.
function get2() return 1, 2 end
function appendMultiple(t, ...)
for i=1, select('#', ...) do
t[#t+1] = select(i, ...)
end
end
local t = { }
appendMultiple(t, get2())
appendMultiple(t, get2())
for _,v in pairs(t) do print(v) end
--> 1 2 1 2