iterate over lua table is not working - scripting

I have the following lua table :
t = {name="sandy", age="22", major="computerScience"}
I want to iterate over it, both methods below do NOT work
Method 1
function printAssociateTable(t) print("before the loop") for i,v
in ipairs(t) do
print(v) end end
Method 2
function printAssociateTable2(t) print("before the loop") for k in
ipairs(t) do
print("before the loop")
print(k.. " is " ..t.k) end end
when I call either methods, they print "before the loop". so the problem the program is not entering the loop !
i tried to manually access the table, if i do this :
return t.name
=> gives sandy
return t[name]
=> gives nil
return t["name"]
=> gives sandy !
how can i iterate over my table ? kindly note that both methods work well with a simple array like this
a={"a","b","c","d"}
but i want it to work on my associative array

The ipairs iterator selects only the array elements with integer keys. To iterate over all keys you require pairs, like this:
function printAssociateTable(t)
print("before the loop")
for i,v in pairs(t) do
print(v)
end
end

Related

Compact way to save JuMP optimization results in DataFrames

I would like to save all my variables and dual variables of my finished lp-optimization in an efficient manner. My current solution works, but is neither elegant nor suited for larger optimization programs with many variables and constraints because I define and push! every single variable into DataFrames separately. Is there a way to iterate through the variables using all_variables() and all_constraints() for the duals? While iterating, I would like to push the results into DataFrames with the variable index name as columns and save the DataFrame in a Dict().
A conceptual example would be for variables:
Result_vars = Dict()
for vari in all_variables(Model)
Resul_vars["vari"] = DataFrame(data=[indexval(vari),value(vari)],columns=[index(vari),"Value"])
end
An example of the appearance of the declared variable in JuMP and DataFrame:
#variable(Model, p[t=s_time,n=s_n,m=s_m], lower_bound=0,base_name="Expected production")
And Result_vars[p] shall approximately look like:
t,n,m,Value
1,1,1,50
2,1,1,60
3,1,1,145
Presumably, you could go something like:
x = all_variables(model)
DataFrame(
name = variable_name.(x),
Value = value.(x),
)
If you want some structure more complicated, you need to write custom code.
T, N, M, primal_solution = [], [], [], []
for t in s_time, n in s_n, m in s_m
push!(T, t)
push!(N, n)
push!(M, m)
push!(primal_solution, value(p[t, n, m]))
end
DataFrame(t = T, n = N, m = M, Value = primal_solution)
See here for constraints: https://jump.dev/JuMP.jl/stable/constraints/#Accessing-constraints-from-a-model-1. You want something like:
for (F, S) in list_of_constraint_types(model)
for con in all_constraints(model, F, S)
#show dual(con)
end
end
Thanks to Oscar, I have built a solution that could help to automatize the extraction of results.
The solution is build around a naming convention using base_name in the variable definition. One can copy paste the variable definition into base_name followed by :. E.g.:
#variable(Model, p[t=s_time,n=s_n,m=s_m], lower_bound=0,base_name="p[t=s_time,n=s_n,m=s_m]:")
The naming convention and syntax can be changed, comments can e.g. be added, or one can just not define a base_name. The following function divides the base_name into variable name, sets (if needed) and index:
function var_info(vars::VariableRef)
split_conv = [":","]","[",","]
x_str = name(vars)
if occursin(":",x_str)
x_str = replace(x_str, " " => "") #Deletes all spaces
x_name,x_index = split(x_str,split_conv[1]) #splits raw variable name+ sets and index
x_name = replace(x_name, split_conv[2] => "")
x_name,s_set = split(x_name,split_conv[3])#splits raw variable name and sets
x_set = split(s_set,split_conv[4])
x_index = replace(x_index, split_conv[2] => "")
x_index = replace(x_index, split_conv[3] => "")
x_index = split(x_index,split_conv[4])
return (x_name,x_set,x_index)
else
println("Var base_name not properly defined. Special Syntax required in form var[s=set]: ")
end
end
The next functions create the columns and the index values plus columns for the primal solution ("Value").
function create_columns(x)
col_ind=[String(var_info(x)[2][col]) for col in 1:size(var_info(x)[2])[1]]
cols = append!(["Value"],col_ind)
return cols
end
function create_index(x)
col_ind=[String(var_info(x)[3][ind]) for ind in 1:size(var_info(x)[3])[1]]
index = append!([string(value(x))],col_ind)
return index
end
function create_sol_matrix(varss,model)
nested_sol_array=[create_index(xx) for xx in all_variables(model) if varss[1]==var_info(xx)[1]]
sol_array=hcat(nested_sol_array...)
return sol_array
end
Finally, the last function creates the Dict which holds all results of the variables in DataFrames in the previously mentioned style:
function create_var_dict(model)
Variable_dict=Dict(vars[1]
=>DataFrame(Dict(vars[2][1][cols]
=>create_sol_matrix(vars,model)[cols,:] for cols in 1:size(vars[2][1])[1]))
for vars in unique([[String(var_info(x)[1]),[create_columns(x)]] for x in all_variables(model)]))
return Variable_dict
end
When those functions are added to your script, you can simply retrieve all the solutions of the variables after the optimization by calling create_var_dict():
var_dict = create_var_dict(model)
Be aware: they are nested functions. When you change the naming convention, you might have to update the other functions as well. If you add more comments you have to avoid using [, ], and ,.
This solution is obviously far from optimal. I believe there could be a more efficient solution falling back to MOI.

Lua metatables and metamethod - How to call a different member function

I have the following Class
local PROGRESS = {}
PROGRESS.__index = function(self,key)
if key~="__group" and self.__group[key] then
return self.__group[key]
else
return rawget(self,key)
end
end
What this does is when You access table[key] it performs a lookup in table.__group (which is an object of another class) and returns table.__group[key] ,if it is not nil.
Now I am trying to do the same for member functions.
i.e If I call table:key() a lookup must be performed in table.__group and if the function is present, then table.__group:key() should be called.
How do I accomplish this?
I tried to do this.
local PROGRESS = {}
PROGRESS.__index = function(self,key)
if key~="__group" and self.__group[key] then
local val = self.__group[key]
if type(val) == "function" then
self.__group:val()
return function() end
end
return self.__group[key]
else
return rawget(self,key)
end
end
But there are 2 things wrong here.
I am unable to retrieve the original function's arguments
Event if I just ACCESS table[key].function without calling it, the function will be called
And I've got the feeling that I am trying to complicate things and the solution is way simpler.
Any help is appreciated.
UPDATE
#Mud
The problem with the original code is that the object passed as 'self' to the member function is an object of the new class. Not of the old class.
Consider this code
GROUP_CLASS = {}
GROUP_CLASS.__index = GROUP_CLASS
function GROUP_CLASS:showSum (a,b) print(self);print(a + b) end
group_object = setmetatable({},GROUP_CLASS)
group_object:showSum(1,2)
local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key,value)
if key~="__group" and self.__group[key] then
return self.__group[key]
else
return rawget(self,key)
end
end
progress_object = setmetatable( {__group = group_object} , PROGRESS_CLASS)
progress_object:showSum(3,3)
--progress_object is passed as first argument to showSum. But i need group_object to be passed
In the above code, When progress_object:showSum(3,3) is called,
is it possible to pass group_object (or in other words progress_object.__group) as self instead of progress_object.
Hope that makes sense.
Response to updated post:
progress_object is passed as first argument to showSum. But i need group_object to be passed
If you're going to ignore the state of the object a method is called on, and substitute the state of some other object, why is it even a method on that object? That's like overriding the addition operator to do multiplication, a recipe for confusion.
In other words, you want this:
progress_object:method("foo")
To resolve, via bizarre internal machinery, into this:
group_object:method("foo")
Why not skip a step and just make the latter call?
If you must, you could achieve this by returning a proxy for the method which replaces self with __group
local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key)
local groupval = self.__group[key]
if key == '__group' or not groupval then
return rawget(self,key)
elseif type(groupval) ~= 'function' then
return groupval
else
return function(...)
if self == ... then -- method call
-- replace self argument with __group
return groupval(self.__group,select(2,...))
else
return groupval(...)
end
end
end
end
Response to original post:
How I am trying to do the same for member functions. i.e If I call table:key() a lookup must be performed in table.__group and if the function is present, then table.__group:key() should be called.
How do I accomplish this?
Do nothing. Your original code handles this.
Lua doesn't know what a "member function" is. A member is a member (i.e. an element in a table), and whether the value of that member is a function is irrelevant.
Remember:
obj:method(a,b,c) is exactly equivalent to obj.method(obj,a,b,c)
obj.method is exactly equivalent to obj["method"].
Your code already resolves obj["method"] into obj.__group["method"]
So you're done.
For instance, say we have:
group = {}
function group:showSum (a,b) print(a + b) end
function group:showProduct(a,b) print(a * b) end
Using your first code, we can write:
foo = setmetatable({__group = group}, PROGRESS)
foo:showSum(3,3) -- 6
foo:showProduct(3,3) -- 9
That's it.
Now, as long as we're here, let's look at what your second function is doing:
local val = self.__group[key]
if type(val) == "function" then
self.__group:val()
return function() end
end
First you grab the function value from __group. At this point you're done. Simply return that value, and the caller is going to call that value (i.e. (...)). Instead, you call __group["val"] which is likely a totally different function from __group[key] (unless key=="val"), then you pass the caller a function which does nothing.

Matlab's arrayfun for uniform output of class objects

I need to build an array of objects of class ID using arrayfun:
% ID.m
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
obj.id = id;
end
end
end
But get an error:
>> ids = 1:5;
>> s = arrayfun(#(id) ID(id), ids)
??? Error using ==> arrayfun
ID output type is not currently implemented.
I can build it alternatively in a loop:
s = [];
for k = 1 : length(ids)
s = cat(1, s, ID(ids(k)));
end
but what is wrong with this usage of arrayfun?
Edit (clarification of the question): The question is not how to workaround the problem (there are several solutions), but why the simple syntax s = arrayfun(#(id) ID(id), ids); doesn't work. Thanks.
Perhaps the easiest is to use cellfun, or force arrayfun to return a cell array by setting the 'UniformOutput' option. Then you can convert this cell array to an array of obects (same as using cat above).
s = arrayfun(#(x) ID(x), ids, 'UniformOutput', false);
s = [s{:}];
You are asking arrayfun to do something it isn't built to do.
The output from arrayfun must be:
scalar values (numeric, logical, character, or structure) or cell
arrays.
Objects don't count as any of the scalar types, which is why the "workarounds" all involve using a cell array as the output. One thing to try is using cell2mat to convert the output to your desired form; it can be done in one line. (I haven't tested it though.)
s = cell2mat(arrayfun(#(id) ID(id), ids,'UniformOutput',false));
This is how I would create an array of objects:
s = ID.empty(0,5);
for i=5:-1:1
s(i) = ID(i);
end
It is always a good idea to provide a "default constructor" with no arguments, or at least use default values:
classdef ID < handle
properties
id
end
methods
function obj = ID(id)
if nargin<1, id = 0; end
obj.id = id;
end
end
end

attempt to call method 'print' (a nil value) when implementation OOP in Lua

So, I'm trying to write a simple class in Lua for representing CSV fields:
csv_entry = {}
csv_entry.__index = csv_entry
function csv_entry.create(...)
return arg
end
function csv_entry:tostring()
local str = string.char()
for i,v in ipairs(self) do
if i < #self then
str = str .. v
else
str = str .. v .. ", "
end
end
end
function csv_entry:print()
print(self:tostring())
end
But when I try to use this class like this:
c = csv_entry.create("Volvo", 10000, "Eric")
c:print() -- line 25
I get the error message
lua: csv.lua:25: attempt to call method 'print' (a nil value)
And I can't really figure out the issue here. What am I doing wrong?
You probably meant to do is this:
function csv_entry.create(...)
return setmetatable(arg, csv_entry)
end
Your posted version of cvs_entry.create just returns it's arguments packed into a table, so this code:
c = csv_entry.create("Volvo", 10000, "Eric")
c:print()
Is exactly equivalent to this code:
c = {"Volvo", 10000, "Eric"}
c:print()
c doesn't contain a print entry, so c.print returns nil and c:print() fails because you're trying to "call" nil.
Side note: the implicit arg parameter to variadic functions was removed in Lua 5.1 (6 years ago). The correct way to do this now is:
function csv_entry.create(...)
local arg = {...}
return setmetatable(arg, csv_entry)
end
Or simply:
function csv_entry.create(...)
return setmetatable({...}, csv_entry)
end
As long as we're here: you're going to get no output from csv_entry:tostring because it doesn't return anything. Also, if all you're trying to do is to concatenate a bunch of items with comma separators, you can use table.concat:
function csv_entry:tostring()
return table.concat(self, ', ')
end
I rewrite your code to meet what it is for, it runs OK for me:
csv_entry = {}
function csv_entry:create(...)
o = {content = {}}
self.__index = self;
setmetatable(o, self)
for i = 1, arg.n do
o.content[i] = arg[i];
end
return o;
end
function csv_entry:tostring()
local resStr = ""
for i, v in pairs(self.content) do
resStr = resStr .. v;
if i < #(self.content) then
resStr = resStr .. ", "
end
end
return resStr;
end
function csv_entry:print()
print(self:tostring())
end
c = csv_entry:create("Volvo", 10000, "Eric")
c:print()
Like #Mud said, the create(...) in your code is just a regular call and returns all arguments from ..., if you want csv_entry works like a class, then you have to put codes which set metatable and __index into create(...), and return an instance from csv_entry class

lua call function from a string with function name

Is it possible in lua to execute a function from a string representing its name?
i.e: I have the string x = "foo", is it possible to do x() ?
If yes what is the syntax ?
To call a function in the global namespace (as mentioned by #THC4k) is easily done, and does not require loadstring().
x='foo'
_G[x]() -- calls foo from the global namespace
You would need to use loadstring() (or walk each table) if the function in another table, such as if x='math.sqrt'.
If loadstring() is used you would want to not only append parenthesis with ellipse (...) to allow for parameters, but also add return to the front.
x='math.sqrt'
print(assert(loadstring('return '..x..'(...)'))(25)) --> 5
or walk the tables:
function findfunction(x)
assert(type(x) == "string")
local f=_G
for v in x:gmatch("[^%.]+") do
if type(f) ~= "table" then
return nil, "looking for '"..v.."' expected table, not "..type(f)
end
f=f[v]
end
if type(f) == "function" then
return f
else
return nil, "expected function, not "..type(f)
end
end
x='math.sqrt'
print(assert(findfunction(x))(121)) -->11
I frequently put a bunch of functions in a table:
functions = {
f1 = function(arg) print("function one: "..arg) end,
f2 = function(arg) print("function two: "..arg..arg) end,
...,
fn = function(arg) print("function N: argh") end,
}
Then you can use a string as an table index and run your function like this
print(functions["f1"]("blabla"))
print(functions["f2"]("blabla"))
This is the result:
function one: blabla
function two: blablablabla
I find this to be cleaner than using loadstring(). If you don't want to create a special function table you can use _G['foo'].
loadstring is not the answer here. For starters you would need a return in the string, and other details I won't go into.
THC4k has the right idea; if you have the function name in the variable x, then the call you want is
_G[x](arg1, arg2, ...)
Names are not unique, there can be many functions names foo in different namespaces. But _G['foo'] is foo in the global namespace.
It sounds like you want to do an 'eval', which is supported in Lua like so:
assert(loadstring(x))()
You'll probably want to concatenate the "()" onto x first, though.