Matlab grouping Data into Triples from a 2d Array
-
23-07-2021 - |
Domanda
Is there a smart way grab Values from a 2d Array in Pairs and additionally to that the last number in the row?
My Data (saved in a file) look something similar to this:
0 89 27 100 42 75 8
0 100 7 92 5 68 6
0 67 49 83 100 100 2
35 76 57 100 100 92 5
18 68 50 54 100 19 3
After loading this Data into Matlab I need to group up the Data into Tuples by always taking the Pairs. In this Example it would be:
[0,89],[27,100],[42,75],[0,100],...[100,19]
After the pairing the Data (or meanwhile), I need to add the last Number in the row to the Pairs. The Previous mentioned Data would be altered followingly:
[0,89,8],[27,100,8],[42,75,8],[0,100,6],...[100,19,3]
How would be a smart way to solve this? I personally dislike the extensive use of Loops and think there is a nicer Solution.
Soluzione
Edit: This should do the trick.
M=[0 89 27 100 42 75 8
0 100 7 92 5 68 6
0 67 49 83 100 100 2
35 76 57 100 100 92 5
18 68 50 54 100 19 3]
X = M(:,1:end-1)
Y = M(:,end)
idxOdd = mod(1:size(X,2),2)==1
Xeven=X(:,~idxOdd)
Xodd=X(:,idxOdd)
Yrep = repmat(Y,1,sum(idxOdd))
[Xodd(:) Xeven(:) Yrep(:)]
Altri suggerimenti
I think it's amazing no-one has come up with this one:
M = [
0 89 27 100 42 75 8
0 100 7 92 5 68 6
0 67 49 83 100 100 2
35 76 57 100 100 92 5
18 68 50 54 100 19 3 ];
C = arrayfun(...
@(ii) [M(:,ii:ii+1) M(:,end)], ...
1:2:size(M,2)-1, 'UniformOuput', false);
You'll end up with this cell array:
>> C{1}
ans =
0 89 8
0 100 6
0 67 2
35 76 5
18 68 3
>> C{2}
ans =
27 100 8
7 92 6
49 83 2
57 100 5
50 54 3
>> C{3}
ans =
42 75 8
5 68 6
100 100 2
100 92 5
100 19 3
Now you can refer to individual tuples like so:
C{1}(2,:) % [ 0 100 6]
C{3}(4,:) % [100 92 5]
This can be done using logical indexing. Building off of Dennis's answer:
z = M(:,end); %# extract the last column
M = M(:,1:end-1); %# chop off the last column from the rest of your data
xidx = logical(mod(1:size(M,2),2)); %# get a logical index of the odd numbered rows
x = M(:,xidx); %# grab the x values
y = M(:,~xidx); %# grab the y values
z = repmat(z,1,numel(x)/numel(z)); % replicate z to match numel of x and y
x = reshape(x',numel(x),1); %# reshape the arrays to form the right dimensions
y = reshape(y',numel(y),1);
z = reshape(z',numel(z),1);
output = [x,y,z]; %# format output
For grouping the data in matrix A
, you can use cell2mat
and output an array of cell tuples C
, then append last column elements in corresponding lines in this array:
% separate the data pairs
C = mat2cell(A(:,1:end-1), ones(1,size(A,1)), 2*ones(1,3));
% single for-loop to append line_lat_element in cells of same row
for i = 1:size(A,1)
D(i,:) = cellfun(@(x) [x A(i,end)], {C{i,:}}, 'UniformOutput', false);
end
As output, each D{i,j}
entry of the cell array will contain the triplet [data1 data2 last_element_of_line]
.
I would like to defend the humble for
loop in this case:
M = [ 0 89 27 100 42 75 8 ;
0 100 7 92 5 68 6 ;
0 67 49 83 100 100 2 ;
35 76 57 100 100 92 5 ;
18 68 50 54 100 19 3 ];
out = zeros((size(M,2)-1)/2*size(M,1),3);
ind = 1;
for row = 1:size(M,1)
for col = 1:2:(size(M,2)-1)
out(ind,:) = [M(row,col:col+1) M(row,end)];
ind = ind+1;
end
end
out
I claim that this is easier to write, understand and maintain than the non-loop versions (either for a programmer new to the code, or the same programmer returning to the code weeks, months, or years later). The only slightly-tricky part is calculating the proper size for the output matrix out
. If performance becomes an issue, then sure, look at a non-loop version. But recent versions of MATLAB run for loops much faster than in the past, so why optimize prematurely?
You could eliminate the need to keep a running index by a clever calculation based on row
and col
, but why bother? The above code is simple and easy for a programmer to understand