How to get all unique values in a cell array of matrices? - matlab

I want to get all unique values in A, where A is a cell array of matrices of different shapes and sizes:
A = {[], 1, [2 3], [4 5; 6 7]};
U = [];
for ii = 1: numel(A)
a = A{ii};
U = [U; a(:)];
end
U = unique(U);
That returns:
U =
1 2 3 4 5 6 7
If all elements in A where row vectors, I could use [A{:}] like:
U = unique([A{1:3}]);
That returns:
U =
1 2 3
But in my case it throws an exception:
Error using horzcat
Dimensions of matrices being concatenated are not
consistent.
So how can I avoid that for-loop?

You can use cellfun to reshape all elements in the cell.
U = unique(cell2mat(cellfun(#(x)reshape(x,1,numel(x)),A, 'UniformOutput', false)));
or avoiding the reshapewith
U = unique(cell2mat(cellfun(#(x)x(:).',A, 'UniformOutput', false)));

We can go this way:
A = {[], 1, [2 3], [2 0; 4 5; 6 7]};
AA = cellfun( #(x) unique(x(:)), A, 'UniformOutput' , false)
res = unique(cat(1, AA{:}))
First of all create unique array for each cell - it let us avoid converting all the cells to numeric just only unique values.
Lets convert cell array to one numeric array - cat(1, AA{:}) .
Find unique values through this resulting array.

Related

Finding elements in an array other than given indices

I want to find the elements in an array which are not the given index elements. For example, given an array A = [1 5 7 8], and index ind = [2 3], the operation should return elements [1 8].
Use a direct index vector:
B = A(setdiff(1:numel(A),ind));
Or throw away unneeded elements:
B = A;
B(ind) = [];
Or use logical indexing:
% either
B = A(~any(bsxfun(#eq,ind(:),1:numel(A)),1));
% or
B = A(all(bsxfun(#ne,ind(:),1:numel(A)),1));

Push array onto 2D array (matrix) in MATLAB

For God only knows what reason, we're being asked to use MATLAB in an AI course. All I want to do is initialize an array, and push arrays onto it. In Ruby, this would be:
multi_arr = []
an_arr = [1, 2, 3, 4]
multi_arr << an_arr
Done! Unfortunately I can't find a similarly simple solution in MATLAB.
Any advice would be extremely appreciated.
EDIT: for the interested, here's the rather ungraceful solution I arrived at:
child_states = []
child_state = [0,1,2,3,4,5,6,7,8]
% returns [rows, columns]
dimensions = size(child_states)
child_states(dimensions(1)+1, 1:9) = child_state
You can append array to an array in matlab without knowing the dimensions but it won't be very efficient because matlab will allocate space for the whole array each time you do it. Here's how to do it:
arrays = [];
arr1 = [1,2];
arr2 = [3,4,5];
% append first array
arrays = [arrays ,arr1 ]
% append second array
arrays = [arrays ,arr2 ]
arrays =
1 2
arrays =
1 2 3 4 5
if each of the arrays you want to append have the same length, then you can append them as rows:
arrays = [];
arr1 = [1,2,4];
arr2 = [5,6,7];
% append first array
arrays = [arrays ; arr1 ]
% append second array
arrays = [arrays ; arr2 ]
arrays =
1 2 4
arrays =
1 2 4
5 6 7
for more of a ruby like array appending you should use cell arrays:
cells = {};
cells = [cells ,[4,5] ]
cells = [cells ,[1,1,1] ]
cells = [cells ,['hello']]
cells =
[1x2 double] [1x3 double] 'hello'
GIYF. It seems that you are looking for horzcat and vertcat. Check out MATLAB's doc at Creating and concatenating matrices.; from vertcat page:
C = vertcat(A1,...,AN) vertically concatenates arrays A1,...,AN. All arrays in the argument list must have the same number of columns.
If the inputs are multidimensional arrays, vertcat concatenates N-dimensional arrays along the first dimension. The remaining dimensions must match.
Here's a function that's supposed to do what you want: concatenate a row vector to an array regardless of size. This function will check the dimension along the second axis of input and output array and pad zero to whichever one that is smaller so they can be concatenated along the first axis.
function m = freevertcat(m, n)
if isempty(m)
m = cat(1, m, n);
else
size_m = size(m, 2);
size_n = size(n, 2);
if size_m > size_n
n(size_n+1 : size_n + size_m - size_n) = 0
elseif size_n > size_m
m(:, size_m+1 : size_m + size_n - size_m) = 0;
end
m = cat(1, m, n);
end
example usage
m = []
n = [1,2,3,4,5]
m = freevertcat(m,n)
p = [3,3,3]
m = freevertcat(m,p)
You'll get
m = 1 2 3 4 5
3 3 3 0 0

Find row-wise combinations of a 2 dimensional matrix

I have a matrix:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
I want to find all row-wise combinations of X. i.e.
A(1) = [2, 6, 1; 3, 8, 1; 4, 7, 1]
A(2) = [2, 6, 1; 3, 8, 1; 6, 2, 1]
:
:
:
Here's what I've tried:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3
[m, n] = size(X);
comb = combnk(1:m, p);
[s, t] = size(comb);
c = [X(comb(:,1), :, :) X(comb(:,2), :, :) X(comb(:,3), :, :)];
This gives me a matrix like:
c = 2 6 1 3 8 1 4 7 1
2 6 1 3 8 1 6 2 1
2 6 1 3 8 1 6 4 1
I want to apply the concatenate matrix option to obtain c to make it dynamic depending on value of p but I'm not sure how to use it. I don't want to use For loops. Please help me out.
This is fully vectorized, so it should be fast:
n = 3; %// number of rows to pick each time
ind = reshape(nchoosek(1:size(X,1), n).', [], 1); %'// indices of combinations
A = permute(reshape(X(ind,:).', size(X,2), n, []), [2 1 3]);
The result is
A(:,:,1)
ans =
2 6 1
3 8 1
4 7 1
A(:,:,2)
ans =
2 6 1
3 8 1
6 2 1
etc.
Should you need the result in the form of a cell array, you can convert A from 3D-array to cell array this way:
A = mat2cell(A, size(A,1), size(A,2), ones(1,size(A,3)));
Your thinking is pretty close. This code does the job. I put comments in code, which should be easy to read.
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3;
%// List all combinations choosing 3 out of 1:8.
v = nchoosek(1:size(X,1), p);
%// Use each row of v to create the matrices, and put the results in an cell array.
%// This is the A matrix in your question.
A = arrayfun(#(k)X(v(k,:), :), 1:size(v,1), 'UniformOutput', false);
%// And you can concatenate A vertically to get c.
flatA = cellfun(#(x)reshape(x, 1, []), A, 'UniformOutput', false);
c = vertcat(flatA{:});
PS: From my understanding I thought the result you wanted was A, which is an easy to use cell array. But I added an extra step to get c exactly as in your question just in case.
Disclaimer: arrayfun and cellfun are pretty much equivalent to for loop in terms of performance.
You can do it using reshape and a bunch of transposes since Matlab is column-major ordered:
c = reshape(X(comb',:)',9,[])'
or if you want a 3D matrix:
A = permute(reshape(X(comb',:)',3,3,[])', [2,1,3])

Matlab 2D-Array indexing and replacing

Given array Array_in of size m*n and R of size s*2. Each row in array R corresponds to the starting and ending values of the first column of Array_in and the corresponding column elements in Array_in i.e from Array_in(:,2:end) should not be changed and all remaining elements are replaced by NaN. The first column of the output Array_out is same as the Array_in. The number of rows of array R changes. In the following example the number of rows are assumed to be 2.
Array_in = [0 0.1;1 0.8;2 0.5;3 0.2;4 0.3;5 0.6;6 0.8;7 1;8 1.2;9 1;10 0.1];
R = [2 3;6 9];
R 1st row: should be considered as 2:3 = [2 3];
R 2nd row: as 6:9 = [6 7 8 9]; all the rows i.e [2 3 6 7 8 9] should be retained and
and the expected output is:
Array_out = [0 NaN;1 NaN;2 0.5;3 0.2;4 NaN;5 NaN;6 0.8;7 1;8 1.2;9 1;10 NaN];
How can this be done?
ind = ~any( bsxfun(#ge, Array_in(:,1).', R(:,1)) & ...
bsxfun(#le, Array_in(:,1).', R(:,2)) );
Array_out = Array_in;
Array_out(ind,2:end) = NaN;
Try this -
t1 = bsxfun(#times,1:size(Array_in,1),ones(size(R,1),1))
t2 = bsxfun(#ge,t1,R(:,1)) & bsxfun(#le,t1,R(:,2))
ind = ~any(bsxfun(#eq,Array_in(:,1),find(any(t2))),2)
Array_out = Array_in;
Array_out(ind,2:end)=NaN

How to get a linear array when indexing 3rd or higher dimensions in multidimensional arrays

Consider having the following multidimensional array:
A = [1 2;3 4];
B = [5 6;7 8];
C = cat(3, A, B);
Well it is like a cube, I want to slice the first row, slice the first column and that's it.
When I do:
C(1,1,:)
I get two separate answers:
C(1,1,1) = 1
C(1,1,2) = 5
And if I do
D = C(1,1,:)
I get D to be a multidimensional.
I want this
D = [1 5];
That's it, how to do this?
Use the squeeze() function to drop the extra dimensions:
>> squeeze(C(1,1,:))'
ans =
1 5