Simple indexing in a cell array - matlab

I've constructed a simple Matlab cell array:
d1 =
1
2
3
4
5
d2 =
2
3
4
5
6
d3 =
3
4
5
6
7
d =
[5x1 double]
[5x1 double]
[5x1 double]
clear d1 d2 d3;
How do I access the original array d1 data inside cell array d, after d1 is cleared? If I do:
>> d(1,:)
ans =
[5x1 double]
but what I want to do is issue this command:
d(what indexing goes here?)
and have it return:
1 2 3 4 5

Nevermind, I figured it out:
d{1,1,:}
returns back the original d1 information.

Related

Replace one element of a column in another

Let A and B be column vectors:
A = (1:6).'; %'// [1;2;3;4;5;6]
B = (7:12).'; %'// [7;8;9;10;11;12]
How do I construct a matrix such that one element of A is replaced each time by an element from B to get C as:
C = [...
7 1 1 1 1 1
2 8 2 2 2 2
3 3 9 3 3 3
4 4 4 10 4 4
5 5 5 5 11 5
6 6 6 6 6 12];
If C is to be indexed as index = [1 1 1 2 2 3 3]', how is it possible to produce
c1 = [...
1 7 1 1
1 2 8 2
1 3 3 9];
c2 = [...
2 10 4
2 5 11];
c3 = [3 6]; %// either this
c3 = [3 12]; %// or this
Problem #1:
C = bsxfun(#plus,A.',-diag(A)+diag(B));
gives:
7 2 3 4 5 6
1 8 3 4 5 6
1 2 9 4 5 6
1 2 3 10 5 6
1 2 3 4 11 6
1 2 3 4 5 12
Problem #2:
As far as I understand, you want to extract blocks out of the previously found C matrix, in the following fashion:
Where c1, c2, c3 are the green, red and blue blocks, repectively; and "missing" elements are replaced with NaN (in the initial version of your question).
index = [1 1 1 2 2 3 3]; %// Block definition
[blkSz,~] = histcounts(index,numel(unique(index))); %// Conversion...
paddedC = padarray(C,numel(index)-numel(diag(C))*[1 1],NaN,'post');
blocks = mat2cell(paddedC,blkSz,blkSz);
This results in a cell-array blocks with the following contents:
blocks =
[3x3 double] [3x2 double] [3x2 double]
[2x3 double] [2x2 double] [2x2 double]
[2x3 double] [2x2 double] [2x2 double]
Where for example blocks{1,1} is:
ans =
7 2 3
1 8 3
1 2 9
Then you can pad the array using the index of the loop, to get the c cell, like so:
c = cell(numel(blkSz),1); %// Preallocation
for ind1 = 1:numel(blkSz)
c{ind1} = padarray(blocks{ind1,ind1},1,ind1,'pre');
end
Note that c1 is found in c{1} etc.
Addition:
In the case when you don't want c1...c3 to be (possibly) padded with NaNs, the best way in my opinion would be trimming the index vector to the length of A or B ("length(C)"). This ensures you won't access blocks outside your square matrix. For example:
newIdx = index(1:numel(A));
Then just use newIdx instead of index in the rest of the code.

Assigning a value from a cell array to a numerical arrray

How to assign a value from a cell array to a numerical array efficiently? A and B are always square matrices of any size. For simplicity I just allocated small matrices. If for example A{1}=[2 3 8]; then I want allocate value 8 in second row and third column of the B matrix.
E.g.,
Input
A=[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
[1x3 double] [1x3 double] [1x3 double] [1x3 double]
B=zeros(4,4);
A{1}=[2 3 8];
A{2}=[3 4 7];
and so on...
Output
B(2,3)=8;
B(3,4)=7;
and so on...
Use spconvert:
B = full(spconvert(cat(1, A{:})));
You can do this without loops:
B=zeros(4,4);
A{1}=[2 3 8];
A{2}=[3 4 7];
C = cell2mat(A);
C = reshape(C,3,size(C,2)/3)';
indices = sub2ind(size(B), C(:,1), C(:,2));
B(indices) = C(:,3);
For your example this results in:
B =
0 0 0 0
0 0 8 0
0 0 0 7
0 0 0 0
Using sub2ind and indexing
%// creating a sample cell array. Replace this with your actual cell array
A = {[1 2 8] [1 1 4]; [2 1 5] [2 2 1]};
%// Reshaping the cell array to kx3 matrix
Amat = cat(1,A{:}); %// from luis' answer
%// taking first column as row sub, 2nd col as col sub
%// The subs are converted into linear indices to the size of A or B
ind = sub2ind(size(A),Amat(:,1),Amat(:,2));
%// You have done this (helps in fixing the dimensions of B)
B = zeros(size(A));
%// Taking last col of 'Amat' as values and assigning to corresponding indices
B(ind) = Amat(:,3);
Results:
>> B
B =
4 8
5 1
I would suggest looping once over the A cells to find the maximum index values, let's say max_i,max_j.
Then initialize B like:
B=zeros(max_i,max_j)
And loop again over the A cells and assign th values to the corresponding B elements.
Edit: Added example code:
max_i=0
max_j=0
for k=1:size(A,1)
for l=1:size(A,2)
max_i=max([A{k,l}(1),max_i])
max_j=max([A{k,l}(2),max_j])
end
B=zeros(max_i,max_j)
for k=1:size(A,1)
for l=1:size(A,2)
B(A{k,l}(1),A{k,l}(2))=A{k,l}(3)
end

How to make elements of multiple vectors repeated by MATLAB? [duplicate]

This question already has answers here:
Repeat elements of vector [duplicate]
(3 answers)
Closed 8 years ago.
I have 2 data vectors d1 = [1 2 1 3 4] and d2 = [3 1 2 1], and 2 references howMany1= [3 2 2 1 2] and howMany2 = [2 1 2 2]. The elements of d1 and d2 are to be repeated according to the elements of howMany1 and howMany2: so d1(1) i.e. the first element of d1 should repeat 3 times,d1(2) should repeat 2 times and so on.. and the final result should be d1_repeated = [1 1 1 2 2 1 1 3 4 4] and d2_repeated = [3 3 1 2 2 1 1]
How could I do that in MATLAB? I reviewed the a similar post in which one vector is being repeated, so I tried to do the same and made a for loop. Here is my code:
clear all
close all
clc
% data
d1 = [1 2 1 3 4];
d2 = [3 1 2 1];
howMany1 = [3 2 2 1 2]; % Determines how many times each index in IDX1 should be repeated.
howMany2 = [2 1 2 2];
d = {d1 d2}
howMany = {howMany1 howMany2}
Anew = cell(1,2)
for k = 1:2 % 2 data vectors
Anew{1,k} = arrayfun(#(x) repmat(d{k}(x), howMany{k}(x), 1), 1:numel(d{k}), 'uni', 0);
Anew = vertcat(Anew{:});
end
but I receive the following error:
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Then I tried to change the vert cat to horzcat, but I receive the repetitions as group of doubles:
Anew =
Columns 1 through 7
[3x1 double] [2x1 double] [1] [2x1 double] [2x1 double] [2x1 double] [3]
Column 8
[2x1 double]
Im wondering what is the problem here? Thank you for taking the time.
This can be done by combining ismember and cumsum:
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
Breakdown:
Compare 1:sum(howMany1) with the cumulative sum of howMany1. This is a vector with 1 and 0 that shows the position of where the next value from d1 should start.
ismember(1:sum(howMany1),cumsum([1 howMany1]))
ans =
1 0 0 1 0 1 0 1 1 0
The cumulative sum of this gives a vector that looks like:
cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1])))
ans =
1 1 1 2 2 3 3 4 5 5
Now, this can be used as indices to d1 when creating the d1_repeated.
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
ans =
1 1 1 2 2 1 1 3 4 4

How to repeat and split this vector in MATLAB? [duplicate]

This question already has answers here:
Repeat elements of vector [duplicate]
(3 answers)
Closed 8 years ago.
I have 2 data vectors d1 = [1 2 1 3 4] and d2 = [3 1 2 1], and 2 references howMany1= [3 2 2 1 2] and howMany2 = [2 1 2 2]. The elements of d1 and d2 are to be repeated according to the elements of howMany1 and howMany2: so d1(1) i.e. the first element of d1 should repeat 3 times,d1(2) should repeat 2 times and so on.. and the final result should be d1_repeated = [1 1 1 2 2 1 1 3 4 4] and d2_repeated = [3 3 1 2 2 1 1]
How could I do that in MATLAB? I reviewed the a similar post in which one vector is being repeated, so I tried to do the same and made a for loop. Here is my code:
clear all
close all
clc
% data
d1 = [1 2 1 3 4];
d2 = [3 1 2 1];
howMany1 = [3 2 2 1 2]; % Determines how many times each index in IDX1 should be repeated.
howMany2 = [2 1 2 2];
d = {d1 d2}
howMany = {howMany1 howMany2}
Anew = cell(1,2)
for k = 1:2 % 2 data vectors
Anew{1,k} = arrayfun(#(x) repmat(d{k}(x), howMany{k}(x), 1), 1:numel(d{k}), 'uni', 0);
Anew = vertcat(Anew{:});
end
but I receive the following error:
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Then I tried to change the vert cat to horzcat, but I receive the repetitions as group of doubles:
Anew =
Columns 1 through 7
[3x1 double] [2x1 double] [1] [2x1 double] [2x1 double] [2x1 double] [3]
Column 8
[2x1 double]
Im wondering what is the problem here? Thank you for taking the time.
This can be done by combining ismember and cumsum:
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
Breakdown:
Compare 1:sum(howMany1) with the cumulative sum of howMany1. This is a vector with 1 and 0 that shows the position of where the next value from d1 should start.
ismember(1:sum(howMany1),cumsum([1 howMany1]))
ans =
1 0 0 1 0 1 0 1 1 0
The cumulative sum of this gives a vector that looks like:
cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1])))
ans =
1 1 1 2 2 3 3 4 5 5
Now, this can be used as indices to d1 when creating the d1_repeated.
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
ans =
1 1 1 2 2 1 1 3 4 4

Cell2mat for unequal lengths - MATLAB

I've got a simple 2D cell array that contains data in the form of:
What is the simplest way to be able to use cat/cell2mat when each column can be of an unequal length? Is there a way to replace [] entries with 0?
EDIT:
Desired output would be a matrix with the same number of columns. For the example shown above, the rows in the first column would contain:
42
58
81
19
84
16
40
60
40
36
and so on while the rows of the second column would contain:
57
29
14
5
9
69
17
84
12
4
and so on.
EDIT2:
Adding zeroes would look something like this:
Maybe this is what you want. Zeros are added at the end.
c = {[1;2] [10; 20; 30]; [3;4;5] [40]; [6; 7] []}; %// example
c1 = vertcat(c{:,1});
c2 = vertcat(c{:,2});
n1 = numel(c1);
n2 = numel(c2);
result = zeros(max(n1,n2),2);
result(1:n1,1) = c1;
result(1:n2,2) = c2;
In this example:
>> celldisp(c)
c{1,1} =
1
2
c{2,1} =
3
4
5
c{3,1} =
6
7
c{1,2} =
10
20
30
c{2,2} =
40
c{3,2} =
[]
>> result
result =
1 10
2 20
3 30
4 40
5 0
6 0
7 0
This solution proposes an almost vectorized approach to solve the stated problem and also makes it a generic one for any number of columns in an input cell array. This is categorized as "almost-vectorized" one because it uses cellfun('length'..) (if you look at the code) and AFAIK cellfun is basically a wrapper to a for-loop. But in this case, cellfun('length'..) is very lightweight and rest of the code is vectorized and that's why the term "almost-vectorized".
Code -
%// 3 column sized input cell array
c = {[1;2] [10; 20; 30] [3;8;42]; [3;4;5] [40] [3]; [6; 7] [] [5;9;11;32]}
lens = sum(cellfun('length',c),1)
out = zeros(max(lens),numel(lens))
out(bsxfun(#le,[1:max(lens)]',lens)) = vertcat(c{:})
Output -
>> c
c =
[2x1 double] [3x1 double] [3x1 double]
[3x1 double] [ 40] [ 3]
[2x1 double] [] [4x1 double]
>> out
out =
1 10 3
2 20 8
3 30 42
4 40 3
5 0 5
6 0 9
7 0 11
0 0 32
I would urge you to take a look at cellfun. My solution below would work really well, were it not for the 'UniformOutput', false-part. This is only necessary because some cells in my example are empty matrices, on which histc behaves differently.
cellarray = cell(3,2);
cellarray(:,1)= {[3, 2, 1]; [12, 3, 4, 6]; []};
edges = 1:13; % If you do not know the range of values, find them using cellfun(min, cellarray), and max
x = cellfun(#(x)histc(x, edges), cellarray, 'UniformOutput', false)