I am trying to remove mainMenuButtonGroup1 through mainMenuButtonGroup6.
To do this I think I need to do the following: [mainMenuButtonGroup..n] How would I do that?
local mainMenuButtonGroup1 = { 1,2 }
local mainMenuButtonGroup2 = { 3,4 }
local mainMenuButtonGroup3 = { 5,6 }
local mainMenuButtonGroup4 = { 7,8 }
local mainMenuButtonGroup5 = { 9,10 }
local mainMenuButtonGroup6 = { 11,12 }
for n = 1, 6 do
[mainMenuButtonGroup..n] = nil
end
Based on your comments, I assume this is something like what you want to do, where t is the table that you mentioned.
for i = 1, 6 do
local k = 'mainMenuButtonGroup' .. i
t[k]:removeSelf()
t[k] = nil
end
String concatenation is performed by the .. double period operator, and table indexing via . or []. In this case, you're indexing via [] because you're using a variable and not a constant name.
Edit: Put your similar local variables into a table instead. It makes it far, far easier to iterate as a group. In fact, the only way I know of to iterate locals is through the debug library.
local mainMenuButtonGroup = { {1,2}, {3,4}, {5,6}, {7,8}, {9,10} }
table.insert(mainMenuButtonGroup, {11,12})
for i = 1, 6 do
mainMenuButtonGroup[i] = nil
end
Note, however, that setting a numeric index in a table to nil does not rearrange the table's numerically indexed values. I.e., you'll leave the table with holes. See table.remove.
Assuming the variables are global, they will be in the _G table:
for n = 1, 6 do
for i = _G['mainMenuButtonGroup'..n].numChildren, 1, -1 do
_G['mainMenuButtonGroup'..n][i]:removeSelf()
_G['mainMenuButtonGroup'..n][i] = nil
end
end
If they are local, you can use debug.getlocal, but you will have to loop over all the locals until you find the names you want. Not ideal, but possible.
Related
I have a LUA table:
local tableDatabase = {
name = uniqueName,
class = val_one_to_eight, --not unique
value = mostly_but_not_guaranteed_unique_int}
This table can be sorted by any of the above and may contain a very large data set.
Right now in order to insert I'm just iterating through the table ipairs until I find:
insertedvalue.uniqueName > tableDatabase.uniqueName
--(or comparing the other parms instead if they are the selected sort order.)
I need this function to work super fast. Is there a search algorithm someone could recommend for finding the index into the table to insert or some method I could use that would work on a lua table to optimize this for speed of insertions?
As I know, for strictly ordered structure you can use binary search or similar algorithms.
Lua Users provides ready to use function.
Why don't you create an index on name? If it is not fast enough, you can make __index less generic, i.e. hardcoding the only index on name.
-- Returns a table. ... is a list of fields, for which unique indices should be created:
function indexedTable (...)
local t = {
__indices = {},
__insert = function (self, value) -- instead of table.insert.
self [#self + 1] = value -- implicily calls metamethod __newindex.
end
}
-- Initialise indices:
for _, index in ipairs {...} do
t.__indices [index] = {}
end
setmetatable (t, {
-- Allow t [{name = 'unique'}]:
__index = function (t, key)
if type (key) == 'table' then
for index_key, index_value in pairs (key) do
local value = t.__indices [index_key] [index_value]
if value then
return value
end
end
else
return rawget (t, key)
end
end,
-- Updates all indices on t [k] = v, but doesn't work on table.insert, so use t:__insert"
__newindex = function (t, key, value)
-- insert uniqueness constraint here, if you want.
for index_key, index in pairs (t.__indices) do
index [value [index_key]] = value
end
rawset (t, key, value)
end
})
return t
end
-- Test:
local tableDatabase = indexedTable ('name')
-- Not table.insert, as it is not customizable via metamethods:
tableDatabase:__insert {
name = 'unique1',
class = 1,
value = 'somewhat unique'
}
tableDatabase:__insert {
name = 'unique2',
class = 2,
value = 'somewhat unique'
}
tableDatabase:__insert {
name = 'unique3',
class = 2,
value = 'somewhat unique but not absolutely'
}
local unique2 = tableDatabase [{name = 'unique2'}] -- index search.
print (unique2.name, unique2.class, unique2.value)
I have the following code in Matlab:
a = zeros(23,1)
b = zeros(23,1)
c = zeros(23,1)
How can I write it more compactly? I was looking for a solution that is something like this:
str = {'a','b','c'}
for i = str{i}
i = zeros(23,1)
end
But I can't find a way to do it properly without an error message. Can someone help please?
Here is a compact way using deal :
[a, b, c] = deal(zeros(23,1));
You can also use a struct if the variable name is important:
str = {'a','b','c'};
data = struct
for ii = 1:numel(str)
data.(str{ii}) = zeros(23,1);
end
The struct is more efficient than the table. You can now address data.a, data.b, etc.
But if the name is not useful, it's best to put your data into a cell array:
N = 3;
data = cell(N,1);
for ii = 1:N
data{ii} = zeros(23,1);
end
or simply:
data = cell(3,1);
[data{:}] = deal(zeros(23,1));
Now you address your arrays as data{1}, data{2}, etc., and they're always easy to address in loops.
What you're tempted to do is very bad practise, but can be done like this
str = {'a','b','c'};
for ii = 1:numel(str)
eval( [str{ii} ' = zeros(23,1)'] );
end
Why is this bad practise?
Your code legibility has just gone way down, you can't clearly see where variables are declared.
eval should be avoided
You could use deal to make things a bit nicer, but this doesn't use the array of variable names
[a, b, c] = deal( zeros(23, 1) );
Even better, it's likely you can optimise your code by using a matrix or table instead of separate 1D arrays. The table option means you can still use your variable name array, but you're not using eval for anything!
% Matrix
M = zeros( 23, 3 ); % Index each column as a/b/c using M(:,1) etc
% Table, index using T.a, T.b, T.c
T = array2table( zeros(23,3), 'VariableNames', {'a','b','c'} );
I'm using MATLAB R2009a and following this example:
http://uk.mathworks.com/help/matlab/matlab_external/using-a-matlab-application-as-an-automation-client.html
I'd like to edit it so that I can write a matrix of unknown size into a column in an excel sheet, therefore not explicitly stating the range. I've attempted it this way:
%Put MATLAB data into the worksheet
Hop = [47; 53; 93; 10]; %Pretend I don't know what size this matrix is.
p = length(Hop);
p = strcat('A',num2str(p));
eActivesheetRange = e.Activesheet.get('Range','A1:p');
eActivesheetRange.Value = Hop;
However, this errors out. I've tried several variations of this to no avail. For example, using 'A:B' puts this array in columns A and B in excel and a NAN into every cell beyond my array. As I only want column A filled, using simple ('Range','A') errors out also.
Thanks in advance for any advice you can offer.
You're having issues because you're trying to use your variable p in a string directly
range = 'A1:p';
'A1:p'
This isn't going to work, you want to include the value of p. There are a number of ways you can do this.
In the code you have provided, you have already set p = 'A10' so if you wanted to append that to your range, you'd perform string concatenation
p = 'A10';
range = strcat('A1:', p);
I personally prefer to use sprintf to place the number directly into my strings rather than concatenating a bunch of strings.
p = 10;
range = sprintf('A1:A%d', p)
'A1:A10`
So if we adapt your code to use this we should get
range = sprintf('A1:A%d', numel(Hop));
eActivesheetRange = e.Activesheet.get('Range', range);
eActivesheetRange.Value = Hop;
Also just to be a little explicit, I would use numel rather than length as length is ambiguous. Also, I would flatten Hop into a column vector just to make sure that it's the proper dimension to be written to the spreadsheet.
eActivesheetRange.Value = Hop(:);
Essentially, the idea is to replace xx in 'B1:Bxx' with the number of elements in your matrix.
I tried this:
e = actxserver('Excel.Application');
eWorkbook = e.Workbooks.Add;
e.Visible = 1;
eSheets = e.ActiveWorkbook.Sheets;
eSheet1 = eSheets.get('Item',1);
eSheet1.Activate;
A = [1 2 3 4];
eActivesheetRange = e.Activesheet.get('Range','A1:A4');
eActivesheetRange.Value = A;
The above is directly from the link you shared. The reason why what you are trying to do is failing is that the p you pass into e.Activesheet.get() is a variable and not a string. To avoid this, try the following:
B = randi([0 10],10,1)
eActivesheetRange = e.Activesheet.get('Range',['B1:B' num2str(numel(B))]);
eActivesheetRange.Value = B;
Here, num2str(numel(B)) will pass in a string, which is the number of elements in B. This is variable in the sense that it depends on the number of elements in B.
I have a lot of variables in the base workspace. I have a list of strings containing valid names. So let's say the base workspace contains the variable names var1, var2, var3, var4, var5, var6, var7, var8, var9, var10 and the list of strings is a cell array equal to :
listParam = {'var4' 'var7' 'var10'};
Now, I want to check if the strings that are in listParam have a corresponding declared variable in the base workspace. Here what I have done so far :
function [compareCellArrayList] = test(listParam)
S = evalin('base','whos'); % Looks for the variables in the base workspace
listWorkspaceVariable = cell(size(S)); % Pre-allocate
for ii = 1:length(S)
listWorkspaceVariable{ii,1} = S(ii,1).name; % Gets the variable name of each variable
end
compareCellArrayList = cellfun(#(x) ismember(x, listParam), listWorkspaceVariable, 'UniformOutput', false);
The code above is working correctly, but it's just that i have a feeling it could be simplified while still being easy to understand. Any ideas?
You can replace lines 3 to 6 with
listWorkspaceVariable = {S.name};
Also you can use ismember with two cell arrays so last line can be rewritten
compareCellArrayList = ismember(listWorkspaceVariable, listParam);
so it will be like
function [listWorkspaceVariable] = test(listParam)
S = evalin('base','whos'); % Looks for the variables in the base workspace
listWorkspaceVariable = {S.name};
compareCellArrayList = ismember(listWorkspaceVariable, listParam);
By the way, it seems that your function is not returning compareCellArrayList.
doesexist = ismember(listParam,{S.name})
How would you print() out or find out the index of an object?
For example, if I spawned 20 random rock objects on screen into an array RockTable = {};
Like this RockTable[#RockTable + 1] = rock;
And all 20 rocks are displayed on screen how would I find out what key or index each rock has by clicking on them?
I'm using Corona SDK.
Any help would be greatly appreciated.
Invert the table:
function table_invert(t)
local u = { }
for k, v in pairs(t) do u[v] = k end
return u
end
You can then use the inverted table to find the index.
I find this function so useful that it goes into my permanent "Lua utilities" libraries.
There's another way you can do it, using metamethods.
[Edited to allow you to remove values too]
t = {} -- Create your table, can be called anything
t.r_index = {} -- Holds the number value, i.e. t[1] = 'Foo'
t.r_table = {} -- Holds the string value, i.e. t['Foo'] = 1
mt = {} -- Create the metatable
mt.__newindex = function (self, key, value) -- For creating the new indexes
if value == nil then -- If you're trying to delete an entry then
if tonumber(key) then -- Check if you are giving a numerical index
local i_value = self.r_index[key] -- get the corrosponding string index
self.r_index[key] = nil -- Delete
self.r_table[i_value] = nil
else -- Otherwise do the same as above, but for a given string index
local t_value = self.r_table[key]
self.r_index[t_value] = nil
self.r_table[key] = nil
end
else
table.insert(self.r_index, tonumber(key), value) -- For t[1] = 'Foo'
self.r_table[value] = key -- For t['Foo'] = 1
end
end
mt.__index = function (self, key) -- Gives you the values back when you index them
if tonumber(key) then
return (self.r_index[key]) -- For For t[1] = 'Foo'
else
return (self.r_table[key]) -- For t['Foo'] = 1
end
end
setmetatable(t, mt) -- Creates the metatable
t[1] = "Rock1" -- Set the values
t[2] = "Rock2"
print(t[1], t[2]) -- And *should* proove that it works
print(t['Rock1'], t['Rock2'])
t[1] = nil
print(t[1], t[2]) -- And *should* proove that it works
print(t['Rock1'], t['Rock2'])
It's more versatile as you can copy the t value and take it with you; it also means that you only have to play around with the one variable most of the time - hopefully should reduce the likelihood of you trying to access the wrong thing.
The simplest way is to add an "index" property to each rock:
RockTable = {}
for i=1,20 do
local rock
-- do your thing that generates a new 'rock' object
rock.index = #RockTable + 1
RockTable[rock.index] = rock
end
If you use a touch listener method, you can retrieve the rock this way:
function touchListener( event )
local rock = event.target
local rockIndex = rock.index
-- ...
end
It is true that you can maintain a second table with indices, but I find my method cleaner - when it is time to remove things, you only have to worry about one table, the main one.
I have a question though: why do you need to retrieve that index? In most cases, well designed event listener functions are enough, you don't need to "find" your objects. Of course I lack information on what you are trying to do, but it is possible that you are over-complicating things.
you could do something like this to save you some trouble of constantly looping over a table to find the index...
RockTable = {}
RockIndicies = {}
for i = 1, 20 do
idx = #RockTable + 1
RockTable[idx] = rock
RockIndicies[rock] = idx
end
then when you need to know the index, you can just use the rock you have to index RockIndices to quickly get it. If you 'delete' a rock, you'd want to make sure to remove it in both places.
Unfortunately you'd need to brute the table, to my knowledge. Although, to know that one was clicked, wouldn't you need to be looping them in some way anyway; and therefore already know the index?
Edit
Oh, unless Corona has some sort of callback event for clicking. I've never used it, I've got experience in Lua though.
You could maybe do a backwards reference, like so:
Rocks = {a rock, a rockB, a rockC}
RocksB = {[a rock] = 1, [a rockB] = 2, [a rockC] = 3}
Then just say rockNum = RocksB[rock]
I'm pretty certain that should work but I can't guarantee it, worth a try though.
Edit2
The brute method would look somewhat like:
function getRock(rock)
for _,v in pairs(rocks) do
if (v == rock)
return _
end
end
return "Rock does not exist."
end