How to create idendical variables in MATLAB from an array of variable names? - string

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'} );

Related

MATLAB: Write Dynamic matrix to Excel

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.

How to access a table using a string in Lua

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.

How to compare the workspace variable names with a list of strings (cell array)?

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})

In Lua, how do you find out the key an object is stored in?

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

How to concat string + i?

for i=1:N
f(i) = 'f'+i;
end
gives an error in MatLab. What's the correct syntax to initialize an array with N strings of the pattern fi?
It seems like even this is not working:
for i=1:4
f(i) = 'f';
end
You can concatenate strings using strcat. If you plan on concatenating numbers as strings, you must first use num2str to convert the numbers to strings.
Also, strings can't be stored in a vector or matrix, so f must be defined as a cell array, and must be indexed using { and } (instead of normal round brackets).
f = cell(N, 1);
for i=1:N
f{i} = strcat('f', num2str(i));
end
For versions prior to R2014a...
One easy non-loop approach would be to use genvarname to create a cell array of strings:
>> N = 5;
>> f = genvarname(repmat({'f'}, 1, N), 'f')
f =
'f1' 'f2' 'f3' 'f4' 'f5'
For newer versions...
The function genvarname has been deprecated, so matlab.lang.makeUniqueStrings can be used instead in the following way to get the same output:
>> N = 5;
>> f = strrep(matlab.lang.makeUniqueStrings(repmat({'f'}, 1, N), 'f'), '_', '')
f =
1×5 cell array
'f1' 'f2' 'f3' 'f4' 'f5'
Let me add another solution:
>> N = 5;
>> f = cellstr(num2str((1:N)', 'f%d'))
f =
'f1'
'f2'
'f3'
'f4'
'f5'
If N is more than two digits long (>= 10), you will start getting extra spaces. Add a call to strtrim(f) to get rid of them.
As a bonus, there is an undocumented built-in function sprintfc which nicely returns a cell arrays of strings:
>> N = 10;
>> f = sprintfc('f%d', 1:N)
f =
'f1' 'f2' 'f3' 'f4' 'f5' 'f6' 'f7' 'f8' 'f9' 'f10'
Using sprintf was already proposed by ldueck in a comment, but I think this is worth being an answer:
f(i) = sprintf('f%d', i);
This is in my opinion the most readable solution and also gives some nice flexibility (i.e. when you want to round a float value, use something like %.2f).
according to this it looks like you have to set "N" before trying to use it and it looks like it needs to be an int not string? Don't know much bout MatLab but just what i gathered from that site..hope it helps :)
Try the following:
for i = 1:4
result = strcat('f',int2str(i));
end
If you use this for naming several files that your code generates, you are able to concatenate more parts to the name. For example, with the extension at the end and address at the beginning:
filename = strcat('c:\...\name',int2str(i),'.png');

Resources