How to make specific elements of a cell equal to zero? - matlab

I have a 41 * 41 cell array, and I would like to make the values greater than 0.5 equal to zeros in Matlab, while keeping the rest of the values without any changes. Is it possible to work directly on the cell, or do we need to convert it to a matrix first?
My try
AAA = cell2mat( BBB );
for i = 1: length(AAA)
for j = 1 : i
if AAA(i,j) > 0.5
AAA(i,i) = 0;
else
cc = AAA(i,j);
end
end
end

Here's one-liner to avoid converting the cell array to a matrix and then back to a cell array by calling cell2mat and num2cell/mat2cell.
Assuming an example cell array like this:
BBB = num2cell(rand(41));
Then use cellfun to apply a function to each cell:
CCC = cellfun(#(x)x.*(x<=0.5),BBB,'UniformOutput',false);
This will return a cell array, CCC, the same size as the input, BBB.

Since logical indexing is not supported for operands of type 'cell', you have to convert to matrix first. Use logical indexing on the matrix and convert back to cell. Assuming BBB is like BBB = num2cell(rand(41)), then
AAA = cell2mat(BBB);
AAA(AAA > 0.5) = 0;
BBB = num2cell(AAA)

Related

Check if combination of field values exists in a MATLAB cell array of structs

Suppose I have a cell array containing structs, each with 3 fields.
When I encounter a new struct, I would like to check whether the values in 2 of its 3 fields match those of any struct elements in the array.
cell_array = cell(4,1)
cell_array{1}.Field1 = "ABC"
cell_array{1}.Field2 = 46
cell_array{1}.Field3 = 1648
% Would like to check if fields 1 and 2 match
% any struct in cell_array
new_struct.Field1 = "ABC"
new_struct.Field2 = 46
new_struct.field3 = 1765
Thank you.
You should use Matlab's intersect command. It finds similarities in between two lists of any sort and returns those similarities.
Should then be as simple as:
cell_array = {'ABC', '46', '1648'};
new_array = {'ABC', '46', '1765'};
[C,~,~] = intersect(cell_array,new_array)
disp(C) % C = {'ABC'} {'46'}; 2x1 cell array
% Then simply checking the length of C
if length(C) >= 2
% Perform your task
end

How to convert a each column of a cell array to an array in matlab

I have a cell array C looks like:
start end
------- --------
a b
c d
d a
I need to generate two arrays s=[a,c,d] and t=[b,d,a] from C.
Can you tell me how I can do it in Matlab?
If you have a cell array you can simply grab each column and convert to an array using cellmat
A = cellmat(C(:,1));
B = cellmat(C(:,2));
If the contents of each cell element is non-scalar, you'll need to leave them as a cell, so you'll want to simply use () indexing
A = C(:,1);
B = C(:,2);
However, it looks like you actually have a table in which case you can reference the columns directly
A = C.start;
B = C.end;

How do I find a specific cell within a cell array?

Let's say I have a cell array containing 1x2 cells. eg. deck = {{4,'c'},{6,'s'}...{13,'c'}...{6,'d'}}
How can I find the index of a specific cell? E.g I want to find the index of the cell with the values {13,'c'}.
Thanks!
Try cellfun with isequal:
>> deck = {{4,'c'},{6,'s'},{13,'c'},{6,'d'}};
>> targetCell = {13,'c'};
>> found = cellfun(#(c) isequal(c,targetCell),deck)
found =
0 0 1 0
cellfun let's you check anyway you want (not just isequal). For example, if you want to check based on the string element in each cell:
>> targetLetter = 'c';
>> found = cellfun(#(c) strcmp(c{2},targetLetter),deck)
found =
1 0 1 0
Another method I can suggest is to operate on each column separately. We could use logical operators on each column to search for cards in your cell array that contain a specific number in the first column, followed by a specific suit in the second column. To denote a match, we would check to see where these two outputs intersect. We can do this by combining both outputs with a logical AND when we're done:
deck = {{4,'c'},{6,'s'},{13,'c'},{6,'d'}};
target_card = {13, 'c'};
deck_unroll = vertcat(deck{:});
a1 = cat(1, deck_unroll{:,1}) == target_card{1};
a2 = cat(1, deck_unroll{:,2}) == target_card{2};
found = a1 & a2
found =
0
0
1
0
Because deck is a nested cell array, I unrolled it so that it becomes a 2D cell array where each row denotes one card. This is stored in deck_unroll. Once I do this, I further unroll the cells so that the first column gets placed into a numeric array and we search for a particular number (13 in your example) and the second column gets placed into a string array where we search for a particular character ('c' in your example). This is done with the help of cat to extract each element from a particular column and we construct an array out of these elements.

Initialize a 3D matrix and add new data

Here the code that i have as example:
aaa = [];
bbb = [];
for ii = 1:10
[aaa(:,:,end+1), bbb(:,end+1)] = myfunction();
end
The function myfunction:
function [aaa, bbb] = myfunction()
aaa = rand(5,3);
bbb = rand(5,1);
end
I know i could use ii for sending the output from the variables to aaa and bbb like [aaa(:,:,ii), bbb(:,ii)] = myfunction(). I'm just curious to know why for aaa i generate a 5x3x11 matrix (shouldn't it be 5x3x10?)?. For bbb, it correctly generates a 5x10 matrix. Hence, why the end + 1 works for bbb and not aaa?
I believe this has to do with how MATLAB defines an empty matrix. If you do size(aaa), MATLAB will return 0 0, as you would expect. size(bbb) returns the same. However, if you explicitly try to find the size of the 3rd dimension using size(aaa,3), MATLAB returns 1. So it appears that MATLAB defines an empty matrix as having zero size in the first two dimensions, and a size of 1 in all the other dimensions.
What this means is that when you do a(:,:,end+1), you're actually accessing a(:,:,2), because the end of the 3rd dimension of a is 1, even when it is empty. You don't have this problem with b, because it is only two dimensional, and the end of the second dimension of an empty matrix is zero.
EDIT: As an aside, you should always pre-allocate your matrices if you're going to be assigning values to them in a loop (MATLAB will have complained about this, I believe). If you don't, the matrices have to be resized on every loop iteration, generally resulting in a slower execution time.
I found a solution to my problem. In order to have end+1 work for the third dimension, aaa should be declared as follow:
aaa = zeros(0,0,0);
See this link for further explication on why this works.

sort columns in Matlab

I have 2 columns of data imported from using textscan. The data looks like this where U is undetect and D is detect
mydata=
.51 U
.57 D
.48 U
.47 D
my data = [4x1 double] [4x1 char]
I want to sort the data by the first column and so the data would look like this
.47 D
.48 U
.51 U
.57 D
I would like to preserve the cell structure so that the following command to assign logical value still hold true:
c = zeros(size(mydata,1),1); % preallocate empty matrix
c = mydata{2} == 'U';
for i = 1:size(mydata,1)
curValue = mydata{i,2};
data{i,3} = ~isempty(curValue) && ischar(curValue) && strcmp(curValue ,'U');
end
I read about sortrows but the function is used to sort matrix containing just numbers.
Does anyone have a solution for sorting arrays with a mixture of numbers and characters.
You can SORT by one vector and apply the sorting index to another vector.
[mydata{1},idx] = sort(mydata{1});
mydata{2} = mydata{2}(idx);
I don't think you can directly sort the cell array, because each cell is considered a different "entity". You can always sort the numbers, use the indices to sort the characters, and then put it back in the cell array:
nums = mydata{1};
chars = mydata{2};
[~, ind] = sort(nums);
sortednums = nums(ind);
sortedchars = chars(ind);
mydata{1} = sortednums;
mydata{2} = sortedchars;