How do I remove the elements of one vector from another? - matlab

I have a double value, A, which is
[1,4,7,6]
I also have B, which is an array that contains many more values. I have a new variable, C, which is essentially a double value of all these numbers (all of them in one cell, vs. five).
[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]
How do I remove the elements (not the actual values) from C? I want to end up with this.
[2,6,9,12,3,1,17,13,5,7,13,19,1,5,9,15]
How do I get this? I've used these commands:
C(A) = [];
and
C = C(setdiff(1:length(C),A));
The problem is that when I run that command, I get this instead of what I want.
[4,7,2,12,3,1,17,13,5,7,13,19,1,5,9,15]
Clearly that isn't the same as what I have. It's throwing off the rest of my results and I need to fix this specific issue.
Thanks in advance :)
EDIT:
So I figured out that it's spewing the CORRECT numbers out, just in the wrong order. I have to sort it in order for it to work correctly. This is a problem because it causes the next command to be non-functional because the ismember command has issues with the removal (I don't know why, I'm still working on it).

Double array case
If B is a double array, you can use setdiff with 'rows' and 'stable' options, like so -
C = reshape(setdiff(B,A,'rows','stable').',1,[])
With ismember, you can perform the same operation, like so -
C = reshape(B(~ismember(B,A,'rows'),:).',1,[])
You can also use a bsxfun approach as suggested by #Amro -
C = reshape(B(~all(bsxfun(#eq, B, A),2),:).',1,[])
Cell array case
If B is a cell array with number of elements in each cell equal to the number of elements in A, then you can firstly convert it to a double array - B = vertcat(B{:}) and then use either of the above mentioned tools.
Or you can use a cellfun based approach that avoids conversion to a double array, like so -
excl_rows = B(~cellfun(#(x1,x2) isequal(x1,x2), B, repmat({A},size(B,1),1)),:)
C = horzcat(excl_rows{:})
Or another cellfun based approach that avoids repmat -
exclB = B(~cellfun(#(x1) isequal(x1,A), B),:)
C = horzcat(exclB{:})
Example with explanation -
%// Inputs
A = [1,4,7,6]
B = {[1,4,7,6]
[2,6,9,12]
[3,1,17,13]
[5,7,13,19]
[1,5,9,15]}
%// Compare each cell of B with A for equality.
%// The output must be a binary array where one would be for cells that have
%// elements same as A and zero otherwise.
ind = cellfun(#(x1) isequal(x1,A), B)
%// Thus, ~ind would be a binary array where one would reperesent unequal
%// cells that are to be selected in B for the final output.
exclB = B(~ind)
%// exclB is still a cell array with the cells that are different from A.
%// So, concatenate the elements from exclB into a vector as requested.
C = horzcat(exclB{:})
Output -
A =
1 4 7 6
B =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
ind =
1
0
0
0
0
exclB =
[1x4 double]
[1x4 double]
[1x4 double]
[1x4 double]
C =
2 6 9 12 3 1 17 13 5 7 13 19 1 5 9 15

Related

Pad cell array with whitespace and rearrange

I have a 2D cell-array (A = 2x3) containing numerical vectors of unequal length, in this form:
1x3 1x4 1x2
1x7 1x8 1x3
*Size of A (in both dimensions) can be variable
I want to pad each vector with whitespace {' '} to equalise their lengths to lens = max(max(cellfun('length',A)));- in this case, all vectors will become 1x8 in size - and then subsequently rearrange the cell array into this form so that it can be converted to a columnar table using cell2table (using sample data):
4 1 2 1 3 4
8 5 8 4 7 9
10 12 11 5 [] 11
[] 13 21 7 [] []
[] 15 [] 11 [] []
[] 18 [] 23 [] []
[] 21 [] 29 [] []
[] [] [] 32 [] []
[ ] = Whitespace
i.e. columns are in the order A{1,1}, A{2,1}, A{1,2}, A{2,2}, A{1,3} and A{2,3}.
If A = 4x3, the first five columns after the rearrangement would be A{1,1}, A{2,1}, A{3,1}, A{4,1} and A{1,2}.
My version of Matlab (R2013a) does not have cell2table so like Stewie Griffin I'm not sure which exact format you need for the conversion.
I am also not sure if padding vectors of double with whitespace is such a good idea. strings and double are not convenient to be mixed. Specially if in your case you just want cell array columns of homogeneous type (as opposed to column where each element would be a cell). It means you have to:
convert your numbers to string first (e.g. char array).
since the column will be a char array, they need to be homogeneous in dimension, so you have to find the longest string and make them all the same length.
Finally, you can then pad you char array column with the necessary number of whitespace
One way to do that require multiple cellfun calls to probe for all these information we need before we can actually do the padding/reshaping:
%// get the length of the longest vector
Lmax = max(max(cell2mat(cellfun( #numel , A , 'uni',0)))) ;
%// get the maximum order of magnitude
n = max(max(cell2mat(cellfun( #(x) max(ceil(log10(x))) , A , 'uni',0))))
%// prepare string format based on "n"
fmt = sprintf('%%0%dd',n) ;
%// pad columns with necessary number of whitespace
b = cellfun( #(c) [num2str(c(:),fmt) ; repmat(' ', Lmax-numel(c),n)], A ,'uni',0 ) ;
%// reshape to get final desired result
b = b(:).'
b =
[8x2 char] [8x2 char] [8x2 char] [8x2 char] [8x2 char] [8x2 char]
Note that a call to str2num on that would yield your original cell array (almost, less a reshape operation), as str2num will ignore (return empty) the whitespace entries.
>> bf = cellfun( #str2num , b,'un',0 )
bf =
[3x1 double] [7x1 double] [4x1 double] [8x1 double] [2x1 double] [3x1 double]
If I was dealing with numbers, I would definitely prefer padding with a numeric type (also makes the operation slightly easier). Here's an example padding with 'NaN's:
%// get the length of the longest vector
Lmax = max(max(cell2mat(cellfun( #numel , A , 'un',0)))) ;
%// pad columns with necessary number of NaN
b = cellfun( #(c) [c(:) ; NaN(Lmax-numel(c),1)], A ,'un',0 ) ;
%// reshape to get final desired result
b = b(:).'
b =
[8x1 double] [8x1 double] [8x1 double] [8x1 double] [8x1 double] [8x1 double]
If you do not like operating with NaNs, you could choose a numeric value which is not among the possible values of your dataset. For example if all your values are supposed to be positive integers, -1 is a good indicator of a special value.
%// choose your NULL value indicator
nullNumber = -1 ;
b = cellfun( #(c) [c.' ; zeros(Lmax-numel(c),1)+nullNumber], A ,'un',0 ) ;
b = b(:).'
cell2mat(b)
ans =
4 1 2 1 3 4
8 5 8 4 7 9
10 12 11 5 -1 11
-1 13 21 7 -1 -1
-1 15 -1 11 -1 -1
-1 18 -1 23 -1 -1
-1 21 -1 29 -1 -1
-1 -1 -1 32 -1 -1
Note:
If -1 is a possible value for your set, and you still don't want to use NaN, a value widely used in my industry (which is totally allergic to NaN) as a null indicator for all real numbers is -999.25. Unless you have a very specific application, the probability of getting exactly this value during normal operation is so infinitesimal that it is ok for most software algorithms to recognize a null value when they come across -999.25. (sometimes they use only -999 if they deal with integers only.)
Also note the use of c(:) in the cellfun calls. This makes sure that the vector (in each cell) will be arranged as a column (regardless of it's original shape (because your initial vectors are actually in line as you have them in your example).
Unfortunately, I don't have time to test this, but I believe this should work if you want to do this fast and simple, without having to write explicit loops.
b = cellfun(#(c) [c, repmat(' ', 1, 197-numel(c))], a,'UniformOutput',0)
Edit:
I don't have MATLAB here, and I have never used table before, so I don't know exactly how it works. But, I assume the easiest way to do this is to use the line above, but instead of trying to pad with spaces, pad it with NaNs. After that, when you have made your table with NaNs, you can do something like:
So:
B = A(:); % Straighten it out
C = cellfun(#(c) [c, repmat(NaN, 1, 8-numel(c))], B,'UniformOutput',0) % 1x8 vectors
%% Create table %%
tab(tab == NaN) = ' ';
Sorry if this didn't help. It's all I can do at the moment.
Padding a vector with a white space:
YourString = 'text here';
YourString = [YourString ' '];
in case only 1 whitespace is required. If more are needed you can loop this code to get the wanted number of spaces attached.
table itself already has the functionality to print cells.
Thanks to #StewieGriffin:
[YourString, repmat(' ',1,197-numel(YourString)]

quickly create a cell array with two elements in matlab?

Given two matrices of distinct sizes, say matrices A and B, how to quickly create a cell array to store them? I know how to do this using the standard way as the following.
c = cell(1,2);
c{1}=A,
c{2}=B;
Is there a better way? Basically, what I am asking is to initialize a given cell array quickly in matlab. Many thanks for your time and attention.
You can easily write the statement in one line with C = {A,B}. This creates a cell-array with two columns and one row.
Let's test it with random data:
A = rand(2,2);
B = rand(3,3);
C = {A,B}
This is the result:
C =
[2x2 double] [3x3 double]
In case you need two rows instead of two columns, just change the , to ; like you would do to create a 'normal' matrix.
A = rand(2,2);
B = rand(3,3);
C = {A;B}
This is the result:
C =
[2x2 double]
[3x3 double]
Otherwise you can directly do
C = {A,B};

Matlab: convert cell to readable format

Thanks in advance for the help.
I have an array of values that looks like this
[[1x5 double]; [1x2 double]; ....]
I would like to convert this to this
['12345'; '12'; ....]
cell2mat sort of does what I want, but I end up getting this
[['1' '2' '3' '4' '5']; ['1' '2'];...]
I have been all over the matlab documentation and haven't found a way to do this. Really all I want is to convert [1x5 double] to a string (I can't convert to a num because I don't want to drop insignificant zeros). Is there an simple easy way to do this besides doing this by hand with for loops?
If input_array is your input array, try this cellfun + num2str based approach -
cellfun(#(x) num2str(x,'%1d'), input_array,'uni',0)
Example -
%// Input array
input_array = {randi(9,1,5)-1;randi(9,1,2)-1}
%// Display the cell array values for verification of results later on
celldisp(input_array)
%// Output
out = cellfun(#(x) num2str(x,'%1d'), input_array,'uni',0)
Output (on run) -
input_array =
[1x5 double]
[1x2 double]
input_array{1} =
3 6 0 5 3
input_array{2} =
6 2
out =
'36053'
'62'

MATLAB: Structure containing an column vector won't display the vector

I have defined a structures array as such:
oRandVecs = struct('vV',{[],[]},...
'ind_min',{[],[]},...
'mean',{[],[]},...
'vV_descending',{[],[]},...
'largest_diff',{[],[]});
oRandVecs(1).vV and oRandVecs(2).vv both get column vectors assigned to them. However, the problem is that the output is as follows:
>> oRandVecs(1)
ans =
vV: [4x1 double]
ind_min: 2
mean: 6.5500
vV_descending: [4x1 double]
largest_diff: 2.8000
Instead of actually showing the vector, it only describes its type.
What am I to do?
The reason why is because it's simply too big to display on the screen with that structure :) If you want to actually display it, use dot notation to display your data.
In other words, do this:
disp(oRandVecs(1).vV);
You can also do that with the other variable:
disp(oRandVecs(1).vV_descending);
The answer by rayryeng is probably the way to go.
An alternative is to convert from structure to cell and then use celldisp:
celldisp(struct2cell(oRandVecs(1)))
Example:
>> oRandVecs = struct('vV',{[],[]},...
'ind_min',{[],[]},...
'mean',{[],[]},...
'vV_descending',{[],[]},...
'largest_diff',{[],[]}); %// define empty struct
>> oRandVecs(1).vV = (1:4).'; %'// fill some fields: column vector, ...
>> oRandVecs(1).mean = 5:7; %// ... row vector, ...
>> oRandVecs(1).vV_descending = randn(2,3); %// ... matrix
>> celldisp(struct2cell(oRandVecs(1)))
ans{1} =
1
2
3
4
ans{2} =
[]
ans{3} =
5 6 7
ans{4} =
0.016805198757746 0.236095190511728 0.735153386198679
2.162769508502985 -0.158789830267017 0.661856091557715
ans{5} =
[]

How can I group variables from a mat file by name and collect them in a structure?

I'm reading in a mat file which has variables with a counter e.g. a1, a2, a3, b, c1 and c2.
I want to put the data into a structure with field names "a", "b" and "c" where
a=[a1;a2;a3], b=b and c = [c1; c2].
The algorithm needs to be able to do this, without knowing what the maximum value of the counter of each variable is. How can I do this?
First, you would load your mat file data using the load function, placing it in a structure. Let's say that gave you the following sample data:
>> s = struct('a1',1:5,'b',[],'a2',1:5,'a3',1:5,'c1',1:3,'c2',3:5)
s =
a1: [1 2 3 4 5]
b: []
a2: [1 2 3 4 5]
a3: [1 2 3 4 5]
c1: [1 2 3]
c2: [3 4 5]
Then, we'll order the fields alphabetically using orderfields, find the field names using fieldnames, use regexprep to strip all trailing numbers off of the field names, then get the unique substrings using unique:
>> s = orderfields(s);
>> [strs, inds] = unique(regexprep(fieldnames(s), '\d*$', ''), 'last')
strs =
'a'
'b'
'c'
inds =
3
4
6
Using the indices returned by unique, we can calculate how many times each substring appears by doing diff([0; inds]). Then, we group the structure data into a cell array using these counts and struct2cell and mat2cell:
>> data = mat2cell(struct2cell(s), diff([0; inds]))
data =
{3x1 cell}
{1x1 cell}
{2x1 cell}
Notice that we have a cell array of cell arrays. If you know for sure that each set of entries for each substring will concatenate properly (as in our example), you can concatenate them using cellfun and cell2mat as follows:
>> data = cellfun(#cell2mat, data, 'UniformOutput', false)
data =
[3x5 double]
[]
[2x3 double]
Now we have a cell array of matrices, and a new structure can be made using cell2struct:
>> snew = cell2struct(data, strs)
snew =
a: [3x5 double]
b: []
c: [2x3 double]