MATLAB error - ??? Attempt to reference field of non-structure array - matlab

I'm writing an insertion sort in MATLAB. I called my function like this:
>> A = [5 4 3 2 1]
A =
5 4 3 2 1
>> insertion_sort(A)
but when I run it I get the error
??? Attempt to reference field of non-structure array.
Error in ==> insertion_sort at 6
for j=2:original.length
Here's my original code:
function sorted = insertion_sort(original)
for j=2:original.length
key = original(j);
i = j-1;
while i > 0 && original(i) > key
original(i+1) = original(i);
i = i-1;
end
original(i+1) = key;
end
sorted = original;
end
Anyone know what I'm doing wrong?

Try numel(original) instead of original.length. MatLab matrices are primitive types, not objects, and they don't have a length property.

You want to use numel(original) instead of original.length. Fundamental data types don't have a length method, so MATLAB mistakenly thinks you are trying to access a field named length in a structure, which original is not.

Related

I keep get this error message Unable to perform assignment because value of type 'tf' is not convertible to 'cell'?

num = [1];
dem = [1 1 0 0];
T=[0.1,0.5,2,3,4,20];
ind='A,B,C,D,E,F'
index=strsplit(ind,',')
for i=1:length(T)
for j=1:length(index)
index(j)= tf(num ,dem,'Inputdelay',T(i)); %% error is here
end
for plotId = 1 : 6
subplot(3,2,plotId), bode(index(j))
grid on;
title(['delay=',num2str(T(plotId))])
end
end
Blockquote problem is that i could not using index i heard about somthing call eval but i've got no idea
I don't know much about TensorFlow, which is really what you are asking about, but the reason you get the error is that the type of the variable index becomes a 'cell array' when you use strsplit:
ind='A,B,C,D,E,F'
index=strsplit(ind,',')
ind =
'A,B,C,D,E,F'
index =
1×6 cell array
{'A'} {'B'} {'C'} {'D'} {'E'} {'F'}
Thus, when you try index(j) = tf(...) you are trying to put a type that is not a cell into a variable that is a cell. Matlab doesn't let you do this. For more on cell arrays: https://au.mathworks.com/help/matlab/ref/cell.html.
Results returned from ft have many properties, you must specify which one you need :
for j=1:length(T)
results= tf(num ,dem,'Inputdelay',T(i));
index(j).num =results.num;
index(j).den =results.den;
index(j).Variable =results.Variable;
index(j).ioDelay =results.ioDelay;
index(j).InputDelay =results.InputDelay;
index(j).OutputDelay =results.OutputDelay;
index(j).Ts =results.Ts;
index(j).TimeUnit =results.TimeUnit;
index(j).InputUnit =results.InputUnit;
index(j).InputName =results.InputName;
index(j).InputGroup =results.InputGroup;
index(j).OutputName =results.OutputName;
index(j).OutputUnit =results.OutputUnit;
index(j).OutputGroup =results.OutputGroup;
index(j).Name =results.Name;
index(j).Notes =results.Notes;
index(j).UserData =results.UserData;
index(j).SamplingGrid =results.SamplingGrid;
end

Create array of tf objects in Matlab

If I wanted to create an array of specified class I would use an approach like this. So creating an array of int looks like this:
Aint = int16.empty(5,0);
Aint(1) = 3;
And it works fine. Now I want to create an array of tf class objects. My approach was similar:
L = tf.empty(5, 0);
s = tf('s');
L(1) = s;
This gives me an error:
Error using InputOutputModel/subsasgn (line 57)
Not enough input arguments.
Error in tf_array (line 6)
L(1) = s;
I also made sure to display class(s) and it correctly says it's tf. What do I do wrong here?
As usual, the MATLAB documentation has an example for how to do this sort of thing:
sys = tf(zeros(1,1,3));
s = tf('s');
for k = 1:3
sys(:,:,k) = k/(s^2+s+k);
end
So, the problem likely is that the indexing L(1) is wrong, it needs to be L(:,:,1).
Do note that tf.empty(5, 0) is instructing to create a 5x0 array (i.e. an empty array). There is no point to this. You might as well just skip this instruction. Because when you later do L(:,:,1), you'll be increasing the array size any way (it starts with 0 elements, you want to assign a new element, it needs to reallocate the array). You should always strive to create the arrays of the right size from the start.

Change string values to number in Matlab table

I am using Matlab2015b. And I would like to read a simple csv file to a table and change its string values to corresponding numeric values.
I have following example data.
Var1, VarClass
1 , attack
2 , normal
1, attack
I would like to change this string values to number. for example attack = 1, normal = -1.
My first try.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T(:,2),'attack');
T(rows_attack,2) = 1
rows_normal = strcmp(T(:,2),'normal');
T(rows_normal,2) = -1
I get following error:
Undefined function 'eq' for input arguments of type 'cell'.
What? Which undefined function? What is 'eq'?
Well. After reading some about table, I understood that supposedly higher level matlab does not override '=='. That is 'eq' which means equality. But error message certainly is not informative.
Then my second try.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
T(rows_attack,2) = 1
This time, I get
Right hand side of an assignment into a table must be another table or a cell
array.
Well. Okay. It wants table. I will give it one.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
rows_attack_size = sum(rows_attack);
data_to_fill = ones(rows_attack_size,1) ;
T(rows_attack,2) = array2table(data_to_fill);
Well. This time error message is.
Conversion to cell from double is not possible.
I thought that this matlab table is similar to R data-frame or python pandas DataFrame. Well, certainly it is not. Can someone guide me about how to solve this problem?
My Matlab gives different error message to your code.
>> rows_attack = strcmp(T(:,2),'attack')
rows_attack =
0
>> T(rows_attack,2) = 1
Right hand side of an assignment into a table must be another table or a cell array.
>> T(rows_attack,2)
ans =
empty 0-by-1 table
The error is multi-fold. Applying strcmp on a table does not give a vector; instead it's a scalar 0. When indexing T with zero index it gives an empty table. If neither of these is a problem, then storing a scalar double into a table is a type-not-match.
I didn't get your error message Undefined function 'eq' for input arguments of type 'cell'. from any of my trial. Maybe your matlab environment or version has a different strcmp that has a different overload for tables.
Your second try is
>> rows_attack = strcmp(T.VarClass,'attack')
rows_attack =
1
0
1
>> T(rows_attack,2) = 1
Right hand side of an assignment into a table must be another table or a cell array.
>> T(rows_attack,2)
ans =
VarClass
________
'attack'
'attack'
So this time the error is straightforward. Anyway, it looks like the desired is changing the first row to 1, since those are numbers. However, I got error
>> T(rows_attack,1) =2
Right hand side of an assignment into a table must be another table or a cell array.
Your last try works if respecting the above glitch in addressing the correct column.
>> rows_attack = strcmp(T.VarClass,'attack');
>> rows_attack_size = sum(rows_attack);
>> data_to_fill = ones(rows_attack_size,1) ;
>> T(rows_attack,2) = array2table(data_to_fill);
Conversion to cell from double is not possible.
>> data_to_fill
data_to_fill =
1
1
>> whos ans
Name Size Bytes Class Attributes
ans 2x1 1502 table
>> T(rows_attack,1) = array2table(data_to_fill);
>> T
T =
Var1 VarClass
____ ________
1 'attack'
2 'normal'
1 'attack'
>>
Also, the following also works
>> rows_attack = strcmp(T.VarClass,'attack'); T.Var1(rows_attack) = -1
T =
Var1 VarClass
____ ________
-1 'attack'
2 'normal'
-1 'attack'
Well. Thanks to #Yvon, I found my mistake and solved my problem. Following code works.
T = readtable('example_data.csv', 'Delimiter',',','FileType','text','TreatAsEmpty',{'?'});
rows_attack = strcmp(T.VarClass,'attack');
T.VarClass(rows_attack) = {-1};
rows_normal = strcmp(T.VarClass,'normal');
T.VarClass(rows_normal) = {1};
T.VarClass = cell2mat(T.VarClass);

Nested structure access using dynamic fieldnames

I'd like to achieve the following using dynamic fieldnames instead of setfield:
Say a struct 'myStruct' has a set of nested structures, i.e.
myStruct.a.b.c = 0
myStruct.a.d = 0
myStruct.a.e.f.g = 0
I want to be able to flexibly set the leaf structure values as follows:
fields = {'a', 'b', 'c'}
paramVal = 1
setfield(myStruct, fields{:}, paramVal)
This works using setfield. Is there a syntax that will do this using dynamic fieldnames? The following obviously doesn't work because the fieldname needs to be a string not an array, but demonstrates what I want:
myStruct.(fields{:}) = 0
Which would be equivalent to:
myStruct.('a').('b').('c') = 0
Recursive solution without eval, ripped from one of my old utility functions:
function s = setsubfield(s, fields, val)
if ischar(fields)
fields = regexp(fields, '\.', 'split'); % split into cell array of sub-fields
end
if length(fields) == 1
s.(fields{1}) = val;
else
try
subfield = s.(fields{1}); % see if subfield already exists
catch
subfield = struct(); % if not, create it
end
s.(fields{1}) = setsubfield(subfield, fields(2:end), val);
end
I guess the try/catch can be replaced with if isfield(s, fields{1}) ..., I don't remember why I coded it like that.
Usage:
>> s = struct();
>> s = setsubfield(s, {'a','b','c'}, 55);
>> s = setsubfield(s, 'a.b.d.e', 12)
>> s.a.b.c
ans =
55
>> s.a.b.d.e
ans =
12
Below is a simple, if crude, solution that works for scalar structs. Applying it to your example,
S=setfld(myStruct,'a.b.c',1)
>> S.a.b.c
ans =
1
In general, though, deeply nested structs are unrecommended.
function S=setfld(S,fieldpath,V)
%A somewhat enhanced version of setfield() allowing one to set
%fields in substructures of structure/object S by specifying the FIELDPATH.
%
%Usage: setfld(S,'s.f',V) will set S.s.f=V
%
%
%%Note that for structure S, setfield(S.s,'f') would crash with an error if
%S.s did not already exist. Moreover, it would return a modified copy
%of S.s rather than a modified copy of S, behavior which would often be
%undesirable.
%
%
%Works for any object capable of a.b.c.d ... subscripting
%
%Currently, only single structure input is supported, not structure arrays.
try
eval(['S.' fieldpath '=V;']);
catch
error 'Something''s wrong.';
end

MATLAB "bug" (or really weird behavior) with structs and empty cell arrays

I have no idea what's going on here. I'm using R2006b. Any chance someone out there with a newer version could test to see if they get the same behavior, before I file a bug report?
code: (bug1.m)
function bug1
S = struct('nothing',{},'something',{});
add_something(S, 'boing'); % does what I expect
add_something(S.something,'test'); % weird behavior
end
function add_something(X,str)
disp('X=');
disp(X);
disp('str=');
disp(str);
end
output:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test');
It looks like the emptiness/nothingness of S.something allows it to shift the arguments for a function call. This seems like Very Bad Behavior. In the short term I want to find away around it (I'm trying to make a function that adds items to an initially empty cell array that's a member of a structure).
Edit:
Corollary question: so there's no way to construct a struct literal containing any empty cell arrays?
As you already discovered yourself, this isn't a bug but a "feature". In other words, it is the normal behavior of the STRUCT function. If you pass empty cell arrays as field values to STRUCT, it assumes you want an empty structure array with the given field names.
>> s=struct('a',{},'b',{})
s =
0x0 struct array with fields:
a
b
To pass an empty cell array as an actual field value, you would do the following:
>> s = struct('a',{{}},'b',{{}})
s =
a: {}
b: {}
Incidentally, any time you want to set a field value to a cell array using STRUCT requires that you encompass it in another cell array. For example, this creates a single structure element with fields that contain a cell array and a vector:
>> s = struct('strings',{{'hello','yes'}},'lengths',[5 3])
s =
strings: {'hello' 'yes'}
lengths: [5 3]
But this creates an array of two structure elements, distributing the cell array but replicating the vector:
>> s = struct('strings',{'hello','yes'},'lengths',[5 3])
s =
1x2 struct array with fields:
strings
lengths
>> s(1)
ans =
strings: 'hello'
lengths: [5 3]
>> s(2)
ans =
strings: 'yes'
lengths: [5 3]
ARGH... I think I found the answer. struct() has multiple behaviors, including:
Note If any of the values fields is
an empty cell array {}, the MATLAB
software creates an empty structure
array in which all fields are also
empty.
and apparently if you pass a member of a 0x0 structure as an argument, it's like some kind of empty phantom that doesn't really show up in the argument list. (that's still probably a bug)
bug2.m:
function bug2(arg1, arg2)
disp(sprintf('number of arguments = %d\narg1 = ', nargin));
disp(arg1);
test case:
>> nothing = struct('something',{})
nothing =
0x0 struct array with fields:
something
>> bug2(nothing,'there')
number of arguments = 2
arg1 =
>> bug2(nothing.something,'there')
number of arguments = 1
arg1 =
there
This behaviour persists in 2008b, and is in fact not really a bug (although i wouldn't say the designers intended for it):
When you step into add_something(S,'boing') and watch the first argument (say by selecting it and pressing F9), you'd get some output relating to the empty structure S.
Step into add_something(S.something,'test') and watch the first argument, and you'd see it's in fact interpreted as 'test' !
The syntax struct.fieldname is designed to return an object of type 'comma separated list'. Functions in matlab are designed to receive an object of this exact type: the argument names are given to the values in the list, in the order they are passed. In your case, since the first argument is an empty list, the comma-separated-list the function receives starts really at the second value you pass - namely, 'test'.
Output is identical in R2008b:
>> bug1
X=
str=
boing
X=
test
str=
??? Input argument "str" is undefined.
Error in ==> bug1>add_something at 11
disp(str);
Error in ==> bug1 at 4
add_something(S.something,'test'); % weird behavior