Print all elements of a struct - matlab

I am just approaching Matlab, I have a function with a struct:
function [out] = struct1()
Account(1).name = 'John';
Account(1).number = 321;
Account(1).type = 'Current';
%.......2 to 9
Account(10).name = 'Denis';
Account(10).number = 123;
Account(10).type = 'Something';
for ii= 1:10
out=fprintf('%s\n','%d\n','%s\n',Account{ii}.name, Account{ii}.number,Account{ii}.type);
end
end
The above code gives me an error: "Cell contents reference from a non-cell array object."
How do I output all elements of such struct to get this output using "fprintf"?
name: 'John'
number: 321
type: 'Current'
...... 2 to 9
name: 'Denis'
number: 123
type: 'Something'

You are indexing the elements of the struct array with { and } which are only used for cell arrays. Simple ( and ) will work just fine.
Also, since you have the line breaks in the formatspec, you should just combine all three strings together.
Example:
formatspec = 'name: %s\nnumber: %d\ntype: %s\n';
for ii= 1:10
out=fprintf(formatspec,Account(ii).name,Account(ii).number,Account(ii).type);
end

Related

About save string inside an array

I have question about how can I get from a user multiple inputs(once per line) as a string and save it inside an array ?
I tried something like this :
function[str] = get_data()
st = '';
st{1} = input{'enter the first name','s'};
st{2} = input{'enter the first name','s'};
str = strings(st)
end
Declare your cell beforehand as a cell. Not as a string. Then you can fill it with the inputs.
function[str] = get_data()
st = cell(1,2);
st{1} = input('enter the first name','s');
st{2} = input('enter the last name','s');
str=[st{:}] %if you want to convert it back to a string
%str = strcat(st{1},'_',st{2}) %if you want a _ between the inputs
end
Try the following code:
st = [];
st{1} = input('enter the first name: ','s');
st{2} = input('enter the last name: ','s');
str = strcat(st{1},'_',st{2})

Proper string conversion with implicit data type in MATLAB

I have arbitrary strings that shall be converted to suited data types (i.e. scalar double, double array or string), depending on their content.
str2num() does its job when interpreting the status return value, but the function itself evaluates the content of the string which:
causes str2num('3-7') to be -4 (double), but I want to stick to '3-7' (char array)
is a severe security issue, since it can potentially execute any code
One workaround is to use str2double(), which does not end up with double arrays, but just scalars or strings. Unfortunately, isstrprop() is not really appropriate for this.
Example inputs (and outputs):
'123.4' -> 123.4 (double scalar) [covered by str2double() and str2num()]
abc' -> 'abc' (char array) [inherently covered by str2double() and str2num()]
'123,456' -> [123, 456] (double array) [covered by str2num() only]
'3-7' -> '3-7' (char array) [don't know how to cover]
use str2double and strsplit:
C = {'123.4','abc','123,456','3-7'};
for ii = 1:numel(C)
CC = strsplit(C{ii},',');
res = [str2double(CC)];
if isnan(res)
res = C{ii};
end
disp(res)
disp(class(res))
disp('****************')
end
shows:
123.4000
double
****************
abc
char
****************
123 456
double
****************
3-7
char
****************
Solution (thanks to #user2999345):
function res = str2impl(str, delimiter)
narginchk(1,2);
if isempty(str)
res = [];
return
end
if nargin < 2
delimiter = ',';
end
splits = strsplit(str, delimiter);
res = str2double(splits);
if any(isnan(res)) & ~strcmpi(str, 'NaN') % NaN not specifically requested
res = str;
end
ends up in
C = {'123.4','abc','123,456','3-7','NaN','',[]};
for ii = 1:numel(C)
r{ii,1} = str2impl(C{ii});
end
disp(r)
[ 123.4000]
'abc'
[1×2 double]
'3-7'
[ NaN]
[]
[]

Excel Range object throws error 0x800A03EC because of a string longer than 255 characters

Using an ActiveX server from MATLAB, I am trying to highlight many cells in an Excel sheet at once. These are not in specific columns or rows so I use Range('A1,B2,...') to access them. However the string accepted by the Range object has to be less than 255 characters or an error:
Error: Object returned error code: 0x800A03EC
is thrown. The following code reproduces this error with an empty Excel file.
hActX = actxserver('Excel.Application');
hWB = hActX.Workbooks.Open('C:\Book1.xlsx');
hSheet = hWB.Worksheets.Item('Sheet1');
col = repmat('A', 100, 1);
row = num2str((1:100)'); %'
cellInd = strcat(col, strtrim(cellstr(row)));
str1 = strjoin(cellInd(1:66), ','); %// 254 characters
str2 = strjoin(cellInd(1:67), ','); %// 258 characters
hSheet.Range(str1).Interior.Color = 255; %// Works
hSheet.Range(str2).Interior.Color = 255; %// Error 0x800A03EC
hWB.Save;
hWB.Close(false);
hActX.Quit;
How can I get around this? I found no other relevant method of calling Range, or of otherwise getting the cells I want to modify.
If you start with a String, you can test its length to determine if Range() can handle it. Here is an example of building a diagonal range:
Sub DiagonalRange()
Dim BigString As String, BigRange As Range
Dim i As Long, HowMany As Long, Ln As String
HowMany = 100
For i = 1 To HowMany
BigString = BigString & "," & Cells(i, i).Address(0, 0)
Next i
BigString = Mid(BigString, 2)
Ln = Len(BigString)
MsgBox Ln
If Ln < 250 Then
Set BigRange = Range(BigString)
Else
Set BigRange = Nothing
arr = Split(BigString, ",")
For Each a In arr
If BigRange Is Nothing Then
Set BigRange = Range(a)
Else
Set BigRange = Union(BigRange, Range(a))
End If
Next a
End If
BigRange.Select
End Sub
For i = 10, the code will the the direct method, but if the code were i=100, the array method would be used.
The solution, as Rory pointed out, is to use the Union method. To minimize the number of calls from MATLAB to the ActiveX server, this is what I did:
str = strjoin(cellInd, ',');
isep = find(str == ',');
isplit = diff(mod(isep, 250)) < 0;
isplit = [isep(isplit) (length(str) + 1)];
hRange = hSheet.Range(str(1:(isplit(1) - 1)));
for ii = 2:numel(isplit)
hRange = hActX.Union(hRange, ...
hSheet.Range(str((isplit(ii-1) + 1):(isplit(ii) - 1))));
end
I used 250 in the mod to account for the cell names being up to 6 characters long, which is sufficient for me.

How can I load 100 files with similar names and/or string in just one step in MATLAB?

I have 100 ASCII files in my directory all named as follows:
int_001.ASC
int_002.ASC
int_003.ASC
.
.
.
int_099.ASC
int_100.ASC
I have to import them in MATLAB all with importdata, which should work as follows:
A = importdata('int_001.ASC', ' ', 9)
x = A.data(:,1)
y = A.data(:,2)
My question is: how can I avoid writing 100 times importdata? Is there a way to write the first string only and then have all data uploaded?
Thanks
fls = dir( 'int_*.ASC' );
for fi=1:numel(fls)
A{fi} = importdata( fls(fi).name, ' ', 9 );
% ...
end
UPDATE:
You may use string formatting to read the files according to their numbers:
for fi=1:100
A{fi} = importdata( sprintf('int_%03d.ASC', fi ), ' ', 9 );
% ...
end
You can use strcat function in a for loop :
for k=1:n
fileName = strcat('int_',num2str(k, '%03d'),'.ASC');
A(k) = importdata(fileName, ' ', 9);
x(k) = A(k).data(:,1);
y(k) = A(k).data(:,2);
end
If you want to take this a little overboard:
alldata = arrayfun(...
#(dirEntry)importdata(dirEntry.name, ' ', 9), ...
dir('int_*.ASC'),...
'uniformoutput',false);
This line does the following
Gets a listing of all files matching the partial filename, as an array of structures (h/t Shai)
For each element in that array, performs the importdata call from your original post.
Compiles all the outputs into a cell array.

Prefix match in MATLAB

Hey guys, I have a very simple problem in MATLAB:
I have some strings which are like this:
Pic001
Pic002
Pic003
004
Not every string starts with the prefix "Pic". So how can I cut off the part "pic" that only the numbers at the end shall remain to have an equal format for all my strings?
Greets, poeschlorn
If 'Pic' only ever occurs as a prefix in your strings and nowhere else within the strings then you could use STRREP to remove it like this:
>> x = {'Pic001'; 'Pic002'; 'Pic003'; '004'}
x =
'Pic001'
'Pic002'
'Pic003'
'004'
>> x = strrep(x, 'Pic', '')
x =
'001'
'002'
'003'
'004'
If 'Pic' can occur elsewhere in your strings and you only want to remove it when it occurs as a prefix then use STRNCMP to compare the first three characters of your strings:
>> x = {'Pic001'; 'Pic002'; 'Pic003'; '004'}
x =
'Pic001'
'Pic002'
'Pic003'
'004'
>> for ii = find(strncmp(x, 'Pic', 3))'
x{ii}(1:3) = [];
end
>> x
x =
'001'
'002'
'003'
'004'
strings = {'Pic001'; 'Pic002'; 'Pic003'; '004'};
numbers = regexp(strings, '(PIC)?(\d*)','match');
for cc = 1:length(numbers);
fprintf('%s\n', char(numbers{cc}));
end;