Delete entire rows in struct array matlab depending on field entry - arrays

I have the 1x1008 struct array EEG.event with fields
latency
duration
channel
bvtime
bvmknum
type
code
urevent
I want to delete all rows where entry in field EEG.event.type = 'boundary' or 'R 1'
I tried the following loop:
for b = 1:length(EEG.event)
if strcmp(EEG.event(b).type, 'boundary')
EEG.event(b) = [];
elseif strcmp(EEG.event(b).type, 'R 1')
EEG.event(b) = [];
end
end
This does not work of course, since the counting variable b at some point exceeds the length of EEG.event.
Does anyone have an idea how to delete particular rows?

The fundamental issue that you are having is that you are modifying the same array of structs that you are trying to loop through. This is generally a bad idea and will lead to the issue that you are seeing.
The easiest way to do this is to actually convert the event.type fields of all structs to a cell array, and use strcmp on all of them simultaneously to construct a logical matrix that you can use to index into EEG.event to get the entries you care about.
You can put all of the type values in a cell array like this
types = {EEG.event.type};
Then create your logical array by looking for event types of 'boundary'
isBoundary = strcmp(types, 'boundary');
And get the subset of EEG.event entries like this.
boundaryEvents = EEG.event(isBoundary);
If you want a subset of your events where the type isn't 'boundary' or 'R 1', then you can get that subset this way.
isBoundary = strcmp(types, 'boundary');
isR1 = strcmp(types, 'R 1');
% Keep the entries that aren't boundary or R1 types
events_to_use = EEG.event(~(isBoundary | isR1));

Change your loop to iterate backward through the array, deleting elements toward the end first:
for b = length(EEG.event):-1:1
...

Thanks all for your answers!
This straight forward line of code does the job:
[ EEG.event( strcmp( 'boundary', { EEG.event.type } ) | strcmp( 'R 1', { EEG.event.type } ) ) ] = [];
Cheers!

Related

Automatically assign number to each string in array in Matlab

I have a large cell array in Matlab (imported from Excel) containing numbers and strings.
Let's say the string part looks like this, just bigger with many columns and lines:
Table{1,1} = 'string A'
Table{2,1} = 'string B'
Table{3,1} = 'string B'
And the number part looks like this just bigger:
Table{1,2} = 5;
Table{2,2} = 10;
Table{3,2} = 15;
I am aware that there are disadvantages of working with arrays (right?), so I consider converting EVERYTHING to a numeric matrix by replacing the strings with numbers. (Possibly as a data set with headings - if you don't advise against that?)
My problem is that I have A LOT of different string entries, and I want to automatically assign a number to each entry, e.g. 1 for 'string A', 2 for 'string B' etc., such that:
Matrix(1,1) = 1
Matrix(2,1) = 2
Matrix(3,1) = 2
etc.
and for the numbers simply:
Matrix(1,2) = Table{1,2};
Matrix(2,2) = Table{2,2};
Matrix(3,2) = Table{3,2};
For the strings, I cannot assign the numbers by individual code for each string, because there are so many different string entries. Is there a way to "automate" it?
I am aware of this help site, https://ch.mathworks.com/help/matlab/matlab_prog/converting-from-string-to-numeric.html, but haven't found anything else helpful.
How would you do it?
Find the indices of both numbers and character entries in your cell array using isnumeric (or ischar) with cellfun. Then use third output argument of unique (or findgroups which requires R2015b) for assigning numbers to character entries of your cell array. Now just put the numbers into your required matrix as shown below:
tmp = cellfun(#isnumeric,Table); %Indices of Numbers
Matrix = zeros(size(Table)); %Initialising the matrix
[~, ~, ic] = unique(Table(~tmp)); %Assigning numbers to characters
Matrix(~tmp) = ic; %Putting numbers for characters
%Above two lines can be replaced with Matrix(~tmp) = findgroups(Table(~tmp)); in R2015b
Matrix(tmp) = [Table{tmp}]; %Putting numbers as they are

How to name variables in a data array using a for loop

I have an array within an array and I am trying to name the variables using a for loop as there are a lot of variables. When I use the following simple code Time1 = dataCOMB{1,1}{1,1}(1:1024, 1); it opens the first cell in an array and proceeds to open the first cell in the following array and finally defines all the values in column 1 rows 1 to 1024 as Time1. However I have 38 of these different sets of data and when I apply the following code:
for t = 1:38
for aa = 1:38
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
end
end
I get an error
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in Load_Files_working (line 39)
Time(t) = dataCOMB{1,1}{1,aa}(1:1024, 1);
Basically I am trying to get matlab to call the first column in each data set Time1, Time2, etc.
The problem:
1)You'd want to extract in a cell row...
2) ...the first 1024 numbers in the 1st column...
3) ...from each of the first 38 cells of a cell array.
The plan:
1) If one wants to get info from each element of a cell array (that is, an array accessed via {} indexing), one may use cellfun. Calling cellfun(some_function, a_cell_array) will aggregate the results of some_function(a_cell_array{k}) for all possible k subscripts. If the results are heterogeneous (i.e. not having the same type and size), one may use the cell_fun(..., 'UniformOutput', false) option to put them in an output cell array (cell arrays are good at grouping together heterogeneous data).
2) To extract the first 1024 numbers from the first column of an numeric array x one may use this anonymous function: #(x) x(1:1024,1). The x argument will com from each element of a cell array, and our anonymous function will play the role of some_function in the step above.
3) Now we need to specify a_cell_array, i.e. the cell array that contains the first 38 cells of the target. That would be, simply dataCOMB{1,1}(1,1:38).
The solution:
This one-liner implements the plan:
Time = cellfun(#(x) x(1:1024,1), dataCOMB{1,1}(1,1:38), 'UniformOutput', false);
Then you can access your data as in this example:
this_time = Time{3};
Your error is with Time(t). That's not how you create a new variable in matlab. To do exactly what you want (ie, create variables names Time1, Time2, etc...you'll need to use the eval function:
for aa = 1:38
eval(['Time' num2str(aa) '= dataCOMB{1,1}{1,aa}(1:1024,1);']);
end
Many people do not like recommending the eval function. Others wouldn't recommend moving all of your data out of a data structure and into their own independently-named variables. So, to address these two criticisms, a better alternative might be to pull your data out of your complicated data structure and to put it into a simpler array:
Time_Array = zeros(1024,38);
for aa = 1:38
Time_Array(:,aa) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
Or, if you don't like that because you really like the names Time1, Time2, etc, you could create them as fields to a data structure:
Time_Data = [];
for aa = 1:38
fieldname = ['Time' num2str(aa)];
Time_Data.(fieldname) = dataCOMB{1,1}{1,aa}(1:1024,1);
end
And, in response to a comment below by the original post, this method can be extended to further unpack the data:
Time_Data = [];
count = 0;
for z = 1:2;
for aa = 1:38
count = count+1;
fieldname = ['Time' num2str(count)];
Time_Data.(fieldname) = dataCOMB{1,z}{1,aa}(1:1024,1);
end
end

Efficient allocation of cell array in matlab

I have some which converts a cell array of strings into a cell array of characters.
Note. For a number of reasons, both the input (C) and the output (C_itemised) must be cell arrays.
The cell array of strings (C) is as follows:
>> C(1:10)
ans =
't1416933446'
''
't1416933446'
''
't1416933446'
''
't1416933446'
''
't1416933446'
''
I have only shown a portion of the array here. In reality it is ~28,000 rows in length.
I have some code which does this, although it is very inefficient. The cellstr function takes up 72% of the code's time, as it is currently called thousands of times. The code is as follows:
C_itemised=cell(length(C),500);
for i=3:length(C)
temp=char(C{i});
for j=1:length(temp)
C(i-2,j)=cellstr(temp(j));
end
end
I have a feeling that some minor modifications could take out the inner loop, thus cutting down the overall running time substantially. I have tried a number of ways to do this, but I think I keep getting confused about whether to use {} or (), and haven't been able to find anything online that can help me. Can anyone see a way to make the code more efficient?
Please also note that this function is used in conjunction with other functions, and does work, although it is running slower than would be ideal. Therefore, I do not wish to change the format of C_itemised.
EDIT:
(A sample of) the output of my current function is:
C_itemised(1,1:12)
ans =
Columns 1 through 12
't' '1' '4' '1' '6' '9' '3' '3' '4' '4' '6' []
One thing I can suggest is to use the undocumented function sprintfc. This function is hidden from normal use in MATLAB, but it is used internally with a variety of other functions. Mainly, if you tried doing help sprintfc, it'll say that there's no function found! It's cool to sniff around the source sometimes!
How sprintfc works is that you provide it a formatting string, much like printf, and the data you want printed. It will take each individual element in the data and place them into individual cell arrays. As an example, supposing I had a string D = 'abcdefg';, if we did:
out = sprintfc('%c', D);
We get:
>> celldisp(out)
out{1} =
a
out{2} =
b
out{3} =
c
out{4} =
d
out{5} =
e
out{6} =
f
out{7} =
g
As such, it takes each element in your string and places them as individual characters serving as individual elements in a new cell array. The %c formatting string means that we want to print a single character per element. Check out the link to Undocumented MATLAB that I posted above if you want to learn more!
Therefore, try simplifying your loop to this:
C_itemised=cell(length(C));
for i=1:length(C)
C_itemised{i} = sprintfc('%c', C{i});
end
C_itemised will be a cell array, where each element C_itemised{i} is another cell array, with each element in this cell array being a single character that is composed of the string C{i}.
Minor Note
You said you were confused about {} and () in MATLAB for cells. {} is used to access individual elements inside the cell. So doing C{1} for example will grab whatever is stored in the first element of the cell array. () is used to slice and index into the cells. For example, if you wanted to make another cell array that is a subset of the current one, you would do something like C(1:3). This will create a three element cell array which is composed of the first three cells in C.

Is there a more efficient way of choosing an element from 1 array and to every element of the same array

I want to, for every element of an array ZAbs, compare it for equality to every element of the array itself and put them into another distinct array. I want the distinct array's elements to have the same index as the ZAbs array.
I did this by creating 4 nested for loops:
for pAbs2 = 1:400
for qAbs2 = 1:300
zAbsCompare = ZAbs(qAbs2, pAbs2);
for pAbs3 = 1:400
for qAbs3 = 1:300
zAbsCompare2 = ZAbs(qAbs3, pAbs3);
if (zAbsCompare == zAbsCompare2)
InitialZModEqualsImag(pAbs2,qAbs2) = InitialZImag(qAbs2, pAbs2);
InitialZModEqualsReal(pAbs2,qAbs2) = InitialZReal(qAbs2, pAbs2);
end
end
end
end
end
However, this runs really slowly. I can't think of a better way to do this, but as I'm inexperienced with MATLAB there's probably something I'm overlooking here. Any help?
EDIT: Fixed an error and restated the question.
You can do the comparison (not sure that's what you want) efficently with bsxfun:
comp = bsxfun(#eq, X, shiftdim(X,-2));
The result comp(m,n,p,q) is 1 if X(m,n) == X(p,q), and 0 otherwise.

Problem with sorting array algorithm

I have three arrays. And I am trying to sort all of them by one of them so. So my arrays are itemarray, pricearray, quantityarray. I want itemarray to be sorted but the corresponding arrays aren't sorting appropriately along with itemarray.
Here is the algorithm I created. Do you know how I can fix this??
DO i=1, NumItems-1
SmallestItem = MINVAL(itemarray(i:NumItems))
MINLOC_array = MINLOC(itemarray(i:NumItems))
Locationsmallest = (i-1)+MINLOC_array(1)
itemarray(Locationsmallest) = itemarray(i)
itemarray(i) = SmallestItem
pricearray(Locationsmallest) = pricearray(i)
pricearray(i) = SmallestItem
quantityarray(Locationsmallest) = quantityarray(i)
quantityarray(i) = SmallestItem
END DO
You are setting pricearray(i) to something that came from itemarray. You should be swapping pricearray(Locationsmallest) and pricearray(i), which you can do by storing the value of pricearray(Locationsmallest) in a temporary variable.
The same is true for quantityarray(i).
By the way, this is an O(n^2) algorithm, and is likely to be very slow when there are a large number of values in your array.

Resources