what's this matlab code doing? - matlab

I'm fairly new to matlab and wrote this following code:
datadir=('/.../prod/balanceSheet/DB/');
seriesnames = {'a.m','b.m','c.m','d.m','f.m','g.m','h.m','i.m'};
for proj=1:5;
database='';
switch proj
case 1
database=strcat(datadir,'scenario1');
case 2
database=strcat(datadir,'scenario2');
case 3
database=strcat(datadir,'scenario3');
case 4
database=strcat(datadir,'scenario4');
case 5
database=strcat(datadir,'scenario5');
end;
database;
gooddatanames={};
a=length(seriesnames);
for i=1:a
gooddatanames={gooddatanames,database,seriesnames(i)};
end
end
this is my first time using a switch. basically what I'm trying to do is to take series from databases (1,2,3,...) such that all series are subject to all scenarios. I'm missing the function that would pull the data but is the above code doing the intended?

Change:
gooddatanames={gooddatanames,database,seriesnames(i)};
to
gooddatanames={gooddatanames{:},database,seriesnames{i}};
and move gooddatanames = {} outside of the loop, and then it does what I think you expect, which is to produce a 1x80 cell array with alternating folders and file names.
More likely, make a few more changes, like this:
datadir=('/.../prod/balanceSheet/DB/');
seriesnames = {'a.m','b.m','c.m','d.m','f.m','g.m','h.m','i.m'};
gooddatanames={};
for proj=1:5;
database='';
switch proj
case 1
database=fullfile(datadir,'scenario1');
case 2
database=fullfile(datadir,'scenario2');
case 3
database=fullfile(datadir,'scenario3');
case 4
database=fullfile(datadir,'scenario4');
case 5
database=fullfile(datadir,'scenario5');
end;
for i=1:length(seriesnames);
gooddatanames{end+1} = fullfile(database,seriesnames{i});
end
end
which results in a 1x40 array of full paths to the individual files.

I agree with what Pursuit has written, though I would like to add that your for/switch structure is a little silly. If you effectively have to enumerate all of them, as you do with the 'switch' as you've implemented it, there's no reason not to take the for/switch loops out entirely and just leave yourself with the commands. One possible alternative would be to replace the entire unnecessary "switch" with:
database = fullfile(datadir, ['scenario', num2str(proj)]);

Related

Only add existing variables in Matlab

I would like to add the sums of 5 one-column arrays in Matlab. The catch is that depending on previous inputs, any of these arrays may or may not exist, thus throwing an error when I try to add the sums of these arrays for post-processing.
After doing some digging I found the following function which I can use to return a logical statement if a certain variable exists in the workspace:
exist('my_variable','var') == 1
I'm not sure this helps me in this case though - Currently the line in which I add the sums of the various arrays looks as follows:
tot_deviation = sum(var1) + sum(var2) + sum(var3) + sum(var4) + sum(var4);
Is there a short way to add only the sums of the existing arrays without excessive loops?
Any help would be appreciated!
You can use if statements:
if ~exist('var1','var'), var1 = 0;end
if ~exist('var2','var'), var2 = 0;end
if ~exist('var3','var'), var3 = 0;end
if ~exist('var4','var'), var4 = 0;end
tot_deviation = sum(var1) + sum(var2) + sum(var3) + sum(var4) + sum(var4);
To my knowledge there is no quick way to do this in matlab. It seems to me that, depending on the structure of your code, you have the following alternatives:
1- Initialize all your variables to column arrays of zeros with something like
var = zeros(nbLines, 1);
2- Put all your columns vectors side to side in a single array and the use tot_deviation = sum(sum(MyArray)); which will work no matter how many columns and lines there is in the array.
3- If you pass your variables to a function you can check the number of inputs arguments inside the function using 'nargin' and then only proceed to sum the right number of variables.
I would recommend using the second method for it seem to me that it is the one that allows you to take the most advantage of matlab's array system which good.
The most robust solution is to initialise all of your variables to 0 at the top of the function. Then there is no chance they don't exist, and they influence the summation correctly.
Alternatively...
You could (read: shouldn't) use a really nasty eval trick here for flexibility...
vars = {'var1','var2','var3','var4'};
tot = 0;
for ii = 1:numel(vars)
if exist(vars{ii}, 'var')
tot = tot + eval(var);
end
end
I say it's "nasty" because eval should be avoided (read the linked blog). The check on the variable name existence mitigates some of the strife, but it's still not ideal.
As suggested in the MathWorks blog on evading eval, a better option would be a struct with dynamic field names. You could use almost the same syntax as above, but replace the if statement with
if isfield( myStruct, vars{ii} )
tot = tot + myStruct.(vars{ii});
end
This will avoid dynamically named variables and keep your workspace clean!

Assigning a whole DataStructure its nullind array

Some context before the question.
Imagine file FileA having around 50 fields of different types. Instead of all programs using the file, I tried having a service program, so the file could only be accessed by that service program. The programs calling the service would then receive a DataStructure based on the file structure, as an ExtName. I use SQL to recover the information, so, basically, the procedure would go like this :
Datastructure shared by service program :
D FileADS E DS ExtName(FileA) Qualified
Procedure called by programs :
P getFileADS B Export
D PI N
D PI_IDKey 9B 0 Const
D PO_DS LikeDS(FileADS)
D LocalDS E DS ExtName(FileA) Qualified
D NullInd S 5i 0 Array(50) <-- Since 50 fields in fileA
//Code
Clear LocalDS;
Clear PO_DS;
exec sql
SELECT *
INTO :LocalDS :nullind
FROM FileA
WHERE FileA.ID = :PI_IDKey;
If SqlCod <> 0;
Return *Off;
EndIf;
PO_DS = LocalDS;
Return *On;
P getFileADS E
So, that procedure will return a datastructure filled with a record from FileA if it finds it.
Now my question : Is there any way I can assign the %nullind(field) = *On without specifying EACH 50 fields of my file?
Something like a loop
i = 1;
DoW (i <= 50);
if nullind(i) = -1;
%nullind(datastructure.field) = *On;
endif;
i++;
EndDo;
Cause let's face it, it'd be a pain to look each fields of each file every time.
I know a simple chain(n) could do the trick
chain(n) PI_IDKey FileA FileADS;
but I really was looking to do it with SQL.
Thank you for your advices!
OS Version : 7.1
First, you'll be better off in the long run by eliminating SELECT * and supplying a SELECT list of the 50 field names.
Next, consider these two web pages -- Meaningful Names for Null Indicators and Embedded SQL and null indicators. The first shows an example of assigning names to each null indicator to match the associated field names. It's just a matter of declaring a based DS with names, based on the address of your null indicator array. The second points out how a null indicator array can be larger than needed, so future database changes won't affect results. (Bear in mind that the page shows a null array of 1000 elements, and the memory is actually relatively tiny even at that size. You can declare it smaller if you think it's necessary for some reason.)
You're creating a proc that you'll only write once. It's not worth saving the effort of listing the 50 fields. Maybe if you had many programs using this proc and you had to create the list each time it'd be a slight help to use SELECT *, but even then it's not a great idea.
A matching template DS for the 50 data fields can be defined in the /COPY member that will hold the proc prototype. The template DS will be available in any program that brings the proc prototype in. Any program that needs to call the proc can simply specify LIKEDS referencing the template to define its version in memory. The template DS should probably include the QUALIFIED keyword, and programs would then use their own DS names as the qualifying prefix. The null indicator array can be handled similarly.
However, it's not completely clear what your actual question is. You show an example loop and ask if it'll work, but you don't say if you had a problem with it. It's an array, so a loop can be used much like you show. But it depends on what you're actually trying to accomplish with it.
for old school rpg just include the nulls in the data structure populated with the select statement.
select col1, ifnull(col1), col2, ifnull(col2), etc. into :dsfilewithnull where f.id = :id;
for old school rpg that can't handle nulls remove them with the select statement.
select coalesce(col1,0), coalesce(col2,' '), coalesce(col3, :lowdate) into :dsfile where f.id = :id;
The second method would be easier to use in a legacy environment.
pass the key by value to the procedure so you can use it like a built in function.
One answer to your question would be to make the array part of a data structure, and assign *all'0' to the data structure.
dcl-ds nullIndDs;
nullInd Ind Dim(50);
end-ds;
nullIndDs = *all'0';
The answer by jmarkmurphy is an example of assigning all zeros to an array of indicators. For the example that you show in your question, you can do it this way:
D NullInd S 5i 0 dim(50)
/free
NullInd(*) = 1 ;
Nullind(*) = 0 ;
*inlr = *on ;
return ;
/end-free
That's a complete program that you can compile and test. Run it in debug and stop at the first statement. Display NullInd to see the initial value of its elements. Step through the first statement and display it again to see how the elements changed. Step through the next statement to see how things changed again.
As for "how to do it in SQL", that part doesn't make sense. SQL sets the values automatically when you FETCH a row. Other than that, the array is used by the host language (RPG in this case) to communicate values back to SQL. When a SQL statement runs, it again automatically uses whatever values were set. So, it either is used automatically by SQL for input or output, or is set by your host language statements. There is nothing useful that you can do 'in SQL' with that array.

Importing much data to Matlab

I have many .txt files like these: "u1.txt", "i3.txt", "p10.txt"... How to load all of these files to matlab, to variables like these: "u1", "u2"... "p1"... Here is my code:
clc, clear all
%% loading data
for j=0:3
switch j
case 0
variable='i';
case 1
variable='u';
case 2
variable='p';
case 3
variable='q';
end
for i=0:15
name = strcat(variable, int2str(i), '.txt')
fid=fopen(name,'r');
data=textscan(fid,'%*s%*s%s%s%s%*s','HeaderLines',10,'CollectOutput',1);
fclose(fid);
data=strrep(data{1},',','.');
data=cellfun(#str2num, data);
end
end
Problem is with variable data - how to change this variable to: "u1", "u2"... "p1"... after every loop?
You could use the variable names u1 u2 etc.. but I would strongly recommend not to do so. Then these consecutive variables u1 to u15 are totally individual variables and basically matlab can not iterate over these variables. For this purpose, I would use a struct which contains cell arrays. Use this line to assign:
allData.(variable){i}=data
And to get your data, instead of u1 use allData.u{1}. These are some more characters to write, but having such structured data results in much simpler code when you use the data.
//Code:
for j=0:3
switch j
case 0
variable='i';
case 1
variable='u';
case 2
variable='p';
case 3
variable='q';
end
for i=0:15
name = strcat(variable, int2str(i), '.txt')
fid=fopen(name,'r');
data=textscan(fid,'%*s%*s%s%s%s%*s','HeaderLines',10,'CollectOutput',1);
fclose(fid);
data=strrep(data{1},',','.');
data=cellfun(#str2num, data);
allData.(variable){i}=data;
end
end
Use eval.
For example:
x = input('Enter the name of the new variable: ','s');
eval([x,'=0:4;']);
In your case:
variablename = strcat(variable,int2str(i));
eval([variablename,'=cellfun(#str2num,',variablename,')'];
This is a good read: Creating variables on the run
You could use eval to do this:
eval([name '=textscan(fid,'%*s%*s%s%s%s%*s','HeaderLines',10,'CollectOutput',1);']);
I think that syntax is correct but I'm not sure. You might have to play around with it a bit to get it to work, which is a huge drawback to using eval in the first place. Not to mention the syntax parser can't work with it, making it more difficult to debug.
My recommendation would be to utilize MATLAB's capability to use dynamic fieldnames.
data.(name)=textscan(fid,'%*s%*s%s%s%s%*s','HeaderLines',10,'CollectOutput',1);
Much cleaner and much easier to debug.
My other recommendation is that you evaluate why you need to utilize this naming scheme in the first place. It will be much easier to create an array (numeric or cell) and use that numeric ID as an index rather than include it with the variable name.

Get all top level entry values from NotesView

What is the easiest way to get all top level entry values from a notes view? I have found the property "TopLevelEntryCount" returning the number of alle categories, but I want the values, too.
To iterate the view entries and column values need too much time.
Set ecl = view.Allentries
Set ve = ecl.Getfirstentry()
While Not(ve Is Nothing)
If IsArray(ve.Columnvalues(0)) Then
If flag = "" Then
arr = ve.Columnvalues(0)
Else
arr = ArrayUnique(ArrayAppend(arr, ve.Columnvalues(0)))
End If
Else
'error if arr is not already an array
arr = ArrayUnique(ArrayAppend(arr, ve.Columnvalues(0)))
End If
flag = "1"
Set ve = ecl.Getnextentry(ve)
Wend
Anyone know a faster way? It must not be written in LotusScript, actually I would prefer Java, JS or SSJS.
Idea 1: You can use the NotesViewNavigator class, and call the getFirst() and getNextCategory() methods. This should be faster than walking all the entries.
Idea 2: You can use NotesSession.Evaluate() with a formula that does an #Unique on #DbColumn for the first column of view. That should bring you back an array, and you can get the ubound of the array. Formulas tend to be very fast, but evaluate() has to compile them first, so I don't know if this will be faster or not. The disadvantage of this approach is that for very large views, this could exceed formula language's size limits. But if it does prove to be faster, you could catch the exception and fall-back to the slower method of iterating.
Richard's response is perfect!
For a java version it's almost the same:
see the Domino help for getNextCategory the given example below ViewNavigator really answer your need: link here
The evaluate method is also available in java Session

iterating over multiple intervals Matlab

I'd like to make a loop in Matlab that would work only over user specified intervals of time, instead of simply the whole time. How can one write this loop condition?
regards
Generally you and iterate multiple ways. There are two main ways that I can think of off the top of my head. I will also open this up for community wiki so others can just easily edit this as well.
First, using a simple For loop.
The general syntax is for index = 1:someValue
someValue can really be anything that is greater than 1 in this case. Many times it's simply the last index value of a matrix you're wanting to traverse.
You can modify this as well though! Let's say you want every 3rd index starting with the 2nd position in the matrix. All you have to do is: for index = 2:3:someValue The 3 here tells the loop that it should add 3 to the index at the end of each loop iteration until you get to (or surpass) someValue.
Yet another modfication is traversing backwards. In this case you start at the 'end' and move to the beginning. It would look like this: for index = someValue:-1:1 You can also do every 4th index while going backwards for index = someValue:-4:1.
Obviously you can replace the value between the two : to be a step size that you want. You just have to be aware of potential indexing issues that can arrise. Namely trying to index out of bounds of the matrix or potentially going negative.
Secondly here you can modify the value within the loop itself. Generally this isn't the best idea when you're using a for loop as the value of your indexing variable will be changed by the loop as well as by you within the loop. Many times you'll see this done with a while loop or a do while combo.
A few examples are as follows:
index = 0;
do
{
% some operations
index = index + aNumber;
}while(index <= someValue)
In the above example the loop will continue to loop until the index value index becomes greater than or equal to someValue at the end of the current iteration of the loop. This type of loop will ALWAYS, and I repeat ALWAYS execute at least once.
index = 0;
while(index <= someValue)
{
%some operations
index = index + aNumber;
}
In this case the loop will continue to loop while index satisfies the logical statement here. If the statement isn't true when you try to run the loop for the first time it will not execute at all.
Hope this helps and feel free to ask for any additional clarification if you want it!
Others, please feel free to edit to add additional information or clean up what I might have not explained fully =)
Do you mean something like this:
for i = [1:5 7:10 12:14 21:22]
do_func(i)
end
or even
for i = [1:5 4:7 19:-1:15]
do_func(i)
end
?
If you only want to perform an action when a certain condition is true in a loop, you just need something like:
for i=1:length(arr)
if condition(arr(i))
do_something(arr(i));
end
end