How do I separate an array depending on values in a column? - arrays

Say I have an Mx4 array A where the values in the first column are a number 1 to 12. Now I want to gather the rest of the columns in 12 separate Mx3 arrays depending on which number is in column 1.
How would I go about doing that?

You can use unique and splitapply as follows. The result is a cell array of arrays.
M = [2 11 41 51;
1 10 20 30;
1 62 83 22;
4 73 53 53;
2 84 94 14]; % example data
L = 5; % Group labels are 1:L (L=12 in your case)
[u,~,w] = unique(M(:,1));
result = cell(L,1);
result(u) = splitapply(#(x){x}, M(:,2:end), w);
This gives
>> celldisp(result)
result{1} =
10 20 30
62 83 22
result{2} =
11 41 51
84 94 14
result{3} =
[]
result{4} =
73 53 53
result{5} =
[]

Related

2D matrix to 3D matrix with row to [row, col] mapping

I have a 2D matrix with in the 1st dimension different channels, and in the 2nd dimension time samples. I want to rearrange this to a 3D matrix, with in the 1st and 2nd dimension channels, and in the 3rd time samples.
The channels have to mapped according to a certain mapping. Right now I am using a for-loop to do so, but what would be a no-loop solution?
N_samples = 1000;
N_channels = 64;
channel_mapping = reshape(1:64, [8 8]).';
% Results in mapping: (can also be random)
% 1 2 3 4 5 6 7 8
% 9 10 11 12 13 14 15 16
% 17 18 19 20 21 22 23 24
% 25 26 27 28 29 30 31 32
% 33 34 35 36 37 38 39 40
% 41 42 43 44 45 46 47 48
% 49 50 51 52 53 55 55 56
% 57 58 59 60 61 62 63 64
data = rand(N_channels, N_samples);
data_grid = NaN(8,8, N_samples);
for k = 1:N_samples
tmp = data(:, k);
data_grid(:, :, k) = tmp(channel_mapping);
end
You can do it in one go as follows:
data_grid = reshape(data(channel_mapping, :), 8, 8, []);

How to use nested or double for loop in Matlab to generate new 1D array by comparing Existing 1D array

For example
I have one binary array with size of 9 as b = [0 1 0 1 0 1 1 1 1], Then another array 'm' with size of 7 as m = [21 28 36 45 45 66 66]. Here i want to change all the zeros of 'b' by 1st element of m then replace 1's of b by consecutive elements of 'm' so my output 1D array should be like k = [21 28 21 36 21 45 45 66 66].
Below is my code i really don't know where i did mistake please help me to solve this
b= [0 1 0 1 0 1 1 1 1];
b=b(:);
m = [21 28 36 45 45 66 66];
m = m(:);
k=zeros(size(b));
for i=1:length(b)
for j=2:length(m)
if b(i)==0
k(i)=m(1);
else
k(i)=m(j);
end
end
end
am getting output as
k = [21 66 21 66 21 66 66 66 66]
Use logical indexing instead - it is much faster and more readable:
b = [0 1 0 1 0 1 1 1 1];
m = [21 28 36 45 45 66 66];
k = zeros(size(b));
k(b==0) = m(1); % fill values where b=0 with m(1)
k(b==1) = m(2:sum(b)+1); % fill values where b=1 with consecutive m values
Result:
>> k
k =
21 28 21 36 21 45 45 66 66

How to get the 3rd column in an array by using 1st and 2nd column values as index in Matlab

I have an array with three columns like this:
A B C
10 75 20
30 67 50
85 12 30
98 49 70
I have A and B values, and I want to get the corresponding C value.
For example if I enter (30,67) it should display 50.
Does Matlab have any trick for getting C value?
(my dataset is very large, and I need a fast way)
you can use ismember:
ABC = [10 75 20
30 67 50
85 12 30
98 49 70];
q = [30 67
85 12];
[~, locb] = ismember( q, ABC(:,1:2), 'rows' );
C = ABC(locb,3);
The result you get is
C =
50
30
Note that the code assume all pairs in q can be found in ABC.
Let your input data be defined as
data = [ 10 75 20
30 67 50
85 12 30
98 49 70];
values = [ 30 67];
This should be pretty fast:
index = data(:,1)==values(1) & data(:,2)==values(2); %// logical index to matching rows
result = data(index,3); %// third-column value for those rows
This gives all third-column values that match, should there be more than one.
If you want to specify several pairs of values at once, and obtain all matching results:
index = any(bsxfun(#eq, data(:,1).', values(:,1)), 1) & ...
any(bsxfun(#eq, data(:,2).', values(:,2)), 1);
result = data(index,3);
For example, given
data = [ 10 75 20
30 67 50
85 12 30
98 49 70
30 67 80 ];
values = [ 30 67
98 49];
the result would be
result =
50
70
80
You can create a sparse matrix. This solution only works if C does not contain any zeros and A and B are integers larger 0
A = [10 30 85 98]';
B = [75 67 12 49]';
C = [20 50 30 70]';
S = sparse(A,B,C);
S(10,75) % returns corresponding C-Value if found, 0 otherwise.
Try accumarray:
YourMatrix = accumarray([A B],C,[],#mean,true);
This way YourMatrix will be a matrix of size [max(A) max(B)], with the values of C at YourMatrix(A(ind),B(ind)), with ind the desired index of A and B:
A = [10 30 85 98]';
B = [75 67 12 49]';
C = [20 50 30 70]';
YourMatrix = accumarray([A B],C,[],#mean,true);
ind = 2;
YourMatrix(A(ind),B(ind))
ans =
50
This way, when there is a repetition in A B, it will return the corresponding C value, provided each unique pair of A B has the same C value. The true flag makes accumarray output a sparse matrix as opposed to a full matrix.

Retrieving specific elements in matlab from arrays in MATLAB

I have an array in MATLAB
For example
a = 1:100;
I want to select the first 4 element in every successive 10 elements.
In this example I want to b will be
b = [1,2,3,4,11,12,13,14, ...]
can I do it without for loop?
I read in the internet that i can select the element for each step:
b = a(1:10:end);
but this is not working for me.
Can you help me?
With reshape
%// reshaping your matrix to nx10 so that it has successive 10 elements in each row
temp = reshape(a,10,[]).'; %//'
%// taking first 4 columns and reshaping them back to a row vector
b = reshape(temp(:,1:4).',1,[]); %//'
Sample Run for smaller size (although this works for your actual dimensions)
a = 1:20;
>> b
b =
1 2 3 4 11 12 13 14
To vectorize the operation you must generate the indices you wish to extract:
a = 1:100;
b = a(reshape(bsxfun(#plus,(1:4)',0:10:length(a)-1),[],1));
Let's break down how this works. First, the bsxfun function. This performs a function, here it is addition (#plus) on each element of a vector. Since you want elements 1:4 we make this one dimension and the other dimension increases by tens. this will lead a Nx4 matrix where N is the number of groups of 4 we wish to extract.
The reshape function simply vectorizes this matrix so that we can use it to index the vector a. To better understand this line, try taking a look at the output of each function.
Sample Output:
>> b = a(reshape(bsxfun(#plus,(1:4)',0:10:length(a)-1),[],1))
b =
Columns 1 through 19
1 2 3 4 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43
Columns 20 through 38
44 51 52 53 54 61 62 63 64 71 72 73 74 81 82 83 84 91 92
Columns 39 through 40
93 94

Array contents display in pairs

I have an array for example: A=[01 255 03 122 85 107]; and I want to print the contents as
A=
FF 01
7A 03
6B 55
Basically a read out from a memory. Is there any function in MatLab lib? I need to do this with minimum use of loops.
Use this -
str2num(num2str(fliplr(reshape(A,2,[])'),'%1d'))
Output -
ans =
21
43
65
87
If you only want to print it as characters, use it without str2num, like this -
num2str(fliplr(reshape(A,2,[])'),'%1d')
Output -
ans =
21
43
65
87
General case with zeros padding -
A=[1 2 3 4 5 6 7 8 9 3] %// Input array
N = 3; %// groupings, i.e. 2 for pairs and so on
A = [A zeros(1,N-mod(numel(A),N))]; %// pad with zeros
out = str2num(num2str(fliplr(reshape(A,N,[])'),'%1d'))
Output -
out =
321
654
987
3
Edit for hex numbers :
Ar = A(flipud(reshape(1:numel(A),2,[])))
out1 = reshape(cellstr(dec2hex(Ar))',2,[])'
out2 = [char(out1(:,1)) repmat(' ',[numel(A)/2 1]) char(out1(:,2))]
Output -
out1 =
'FF' '01'
'7A' '03'
'6B' '55'
out2 =
FF 01
7A 03
6B 55

Resources