Iterating Over Unique Values in Matlab - matlab

I've been trying to follow this answer in order to obtain unique strings from a given cell array. However, I'm running into trouble when iterating over these values. I have tried for loops as follows:
[unique_words, ~, occurrences] = unique(words);
unique_counts = hist(occurrences, 1:max(occurrences));
for a=1:numel(unique_words)
word = unique_words{a}
count = unique_counts{a}
result = result + a_struct.(unique_words{a}) + unique_counts{a}
end
When trying to reference the items like this, I receive the error:
Cell contents reference from a non-cell array object.
Changing the curly brackets to round brackets for unique_couts yields the error:
Reference to non-existent field 'N1'.
Changing both unique_words and unique_counts to round brackets yields:
Argument to dynamic structure reference must evaluate to a valid field name.
How am I to iterate over the results of unique?

unique_words is a cell array. unique_counts is a vector. So unique_words should be accessed using curly brackets and unique_counts using round ones. The error that you are getting in this case is related to the a_struct (which is not defined in the question) not having the corresponding field, not the access method.

Related

MATLAB: removing non-unique numbers from a field within a structure

I have a structure in Matlab, each field contains elements with varying numbers of variables. I would like to remove duplicates of numbers that appear within the same field: I know the unique() function and know how to use it to scan through fields one at a time but not an entire field.
I think I want something like:
structure(1:length(structure)).field=unique(structure(1:length(structure)).field
and get
original
field=[1,2,3] [1,4,5] [2,5,8]
to turn into
field=[1,2,3] [4,5] [8]
Maybe a complicated for loop similar to below (isn't working) which would grab the values from the first element in the field, search through each additional element, and if that value is present set it equal to =[];, and iterate through that way?
for n=1:length(RESULTS)
for m=1:length(RESULTS(n).Volumes)
for l=1:length(RESULTS)
for o=1:length(RESULTS(l).Volumes)
if RESULTS(n).Volumes(m)==RESULTS(l).Volumes(o)
RESULTS(l).Volumes(o)=[];
end
end
end
end
end
Thanks!
This is a quick-and-dirty attempt, but you might be able to improve on it. Assume your struct array and field are sa(:).v. I'm also assuming that the field contains a 1xn array of numbers, as in your example. First, make a "joint" array with the concatenation of all field values and filter the non-unique values:
joint = cell2mat({sa.v});
[uniqJoint,~,backIdx] = unique(joint);
The "uniqJoint" array has also been sorted, but the "backIdx" array contains the indices that, if applied to uniqJoint, will rebuild the original "joint" array. We need to somehow connect those to the original indices (i,j) into the struct array and within the field value sa(i).v(j). To do that, I tried creating an array of the same size as "joint" that contains the indices of the struct that originally had the corresponding element in the "joint" array:
saIdx = cell2mat(arrayfun(#(i) i * ones(1,length(sa(i).v)), ...
1:length(sa), 'UniformOutput', false));
Then you can edit (or, in my case, copy and modify the copy of) the struct array to set the field to the values that have not appeared before. To do that, I keep a logical array to mark the indices of "backIdx" as "already used", in which case I skip those values when rebuilding the fields of each struct:
sb = sa;
used = false(length(backIdx));
for i = 1:length(sa)
origInd = find(saIdx == i); % Which indices into backIdx correspond to this struct?
newInd = []; % Which indices will be used?
for curI = backIdx(origInd)
if ~used(curI)
% Mark as used and add to the "to copy" list
used(curI) = true;
newInd(end+1) = curI;
end
end
% Rewrite the field with only the indices that were not used before
sb(i).v = uniqJoint(newInd);
end
In the end, the data in sb(i).v contains the same numbers as sa(i).v without repeats, and removing those that appeared in any previous elements of the struct.

Matlab: adding value into initialized nested struct-cell

I have this structure
Data = struct('trials',{},'time',{},'theta_des',{},'vel_des',{},'trials_number',{},'sample_numbers',{});
Data(1).trials = cell(1,trials_number);
for i=1:trials_number
Data.trials{i} = struct('theta',{},'pos_err',{},'vel',{},'vel_err',{},'f_uparm',{},'f_forearm',{},'m_uparm',{},'m_forearm',{},...
'current',{},'total_current',{},'control_output',{},'feedback',{},'feedforward',{},'kp',{});
end
but when I want to add a value
Data.trials{i}.theta = 27;
I get this error...
A dot name structure assignment is illegal when the structure is empty. Use a subscript on the structure.
Any idea of how to solve it?
Thanks!
If you take a look at the documentation of struct, it says the following statement:
s = struct(field,value) creates a structure array with the specified field and values.
...
...
If any value input is an empty cell array, {}, then output s is an empty (0-by-0) structure.
Because your fields are initialized to {}, these are empty cell arrays, you will get an empty structure, so you are not able to access into the structure as it's empty. If you want to initialize the struct, use the empty braces instead []. In other words, in your for loop, do this:
for i=1:trials_number
Data.trials{i} = struct('theta',[],'pos_err',[],'vel',[],'vel_err',[],'f_uparm',[],'f_forearm' [],'m_uparm',[],'m_forearm',[],...
'current',[],'total_current',[],'control_output',[],'feedback',[],'feedforward',[],'kp',[]);
end
This should properly initialize the structure for you, and you can then access the fields accordingly. As such, if I wanted to initialize theta in the first structure within your cell array:
Data.trials{1}.theta = 27;
This will now work. You can verify the output by:
disp(Data.trials{1}.theta)
27

Looping through documents in matlab

I am attempting to loop through the variable 'docs' which is a cell array that holds strings, i need to make a for loop that colllects the terms in a cell array and then uses command 'lower' and unique to create a dictionary.
Here is the code i've tried sp far and i just get errors
docsLength = length(docs);
for C = 1:docsLength
list = tokenize(docs, ' .,-');
Mylist = [list;C];
end
I get these errors
Error using textscan
First input must be of type double or string.
Error in tokenize (line 3)
C = textscan(str,'%s','MultipleDelimsAsOne',1,'delimiter',delimiters);
Error in tk (line 4)
list = tokenize(docs, ' .,-');
Generically, if you get an "must be of type" error, that means you are passing the wrong sort of input to a function. In this case you should look at the point in your code where this is taking place (here, in tokenize when textscan is called), and doublecheck that the input going in is what you expect it to be.
As tokenize is not a MATLAB builtin function, unless you show us that code we can't say what those inputs should be. However, as akfaz mentioned in comments, it is likely that you want to pass docs{C} (a string) to tokenize instead of docs (a cell array). Otherwise, there's no point in having a loop as it just repeatedly passes the same input, docs, into the function.
There are additional problems with the loop:
Mylist = [list; C]; will be overwritten each loop to consist of the latest version of list plus C, which is just a number (the index of the loop). Depending on what the output of tokenize looks like, Mylist = [Mylist; list] may work but you should initialise Mylist first.
Mylist = [];
for C = 1:length(docs)
list = tokenize(docs{C}, ' .,-');
Mylist = [Mylist; list];
end

assigning values to a field of an structure array in MATLAB

I want to replace the value of the fields in a structure array. For example, I want to replace all 1's with 3's in the following construction.
a(1).b = 1;
a(2).b = 2;
a(3).b = 1;
a([a.b] == 1).b = 3; % This doesn't work and spits out:
% "Insufficient outputs from right hand side to satisfy comma separated
% list expansion on left hand side. Missing [] are the most likely cause."
Is there an easy syntax for this? I want to avoid ugly for loops for such simple operation.
Credits go to #Slayton, but you actually can do the same thing for assigning values too, using deal:
[a([a.b]==1).b]=deal(3)
So breakdown:
[a.b]
retrieves all b fields of the array a and puts this comma-separated-list in an array.
a([a.b]==1)
uses logical indexing to index only the elements of a that satisfy the constraint. Subsequently the full command above assigns the value 3 to all elements of the resulting comma-separated-list according to this.
You can retrieve that the value of a field for each struct in an array using cell notation.
bVals = {a.b};
bVals = cell2mat( bVals );
AFAIK, you can't do the same thing for inserting values into an array of structs. You'll have to use a loop.

If a MATLAB function returns a variable number of values, how can I get all of them as a cell array?

I am writing a function to remove some values from a cell array, like so:
function left = remove(cells, item);
left = cells{cellfun(#(i) ~isequal(item, i), cells)};
But when I run this, left has only the first value, as the call to cells{} with a logical array returns all of the matching cells as separate values. How do I group these separate return values into a single cell array?
Also, perhaps there is already a way to remove a given item from a cell array? I could not find it in the documentation.
You have to use () instead of {} to index the cells:
function left = remove(cells, item)
left = cells(cellfun(#(i) ~isequal(item, i), cells));
Using () for indexing will give you a subset of cells, while using {} will return the contents of a subset of cells as a comma-separated list, and only the first entry of that list will get placed in left in your example.
You can check out this MATLAB documentation for more information on using cell arrays.
EDIT: Response to comment...
If you have an operation that ends up giving you a comma-separated list, you can place the individual elements of the list into cells of a cell array by surrounding the operation with curly braces. For your example, you could do:
left = {cells{cellfun(#(i) ~isequal(item, i), cells)}};
The inner set of curly braces creates a comma-separated list of the contents of cells that are not equal to item, and the outer set then collects this list into a cell array. This will, of course, give the same result as just using parentheses for the indexing, which is the more sensible approach in this case.
If you have a function that returns multiple output arguments, and you want to collect these multiple values into a cell array, then it's a bit more complicated. You first have to decide how many output arguments you will get, or you can use the function NARGOUT to get all possible outputs:
nOut = 3; %# Get the first three output arguments
%# Or...
nOut = nargout(#some_fcn); %# Get all the output arguments from some_fcn
Then you can collect the outputs into a 1-by-nOut cell array outArgs by doing the following:
[outArgs{1:nOut}] = some_fcn(...);
It should be noted that NARGOUT will return a negative value if the function has a variable number of output arguments, so you will have to choose the value for nOut yourself in such a case.