rearranging a matrix in an efficient way
2 views (last 30 days)
Show older comments
Hello, I would like to know what is the best way to extract rows from a matrix but in a specific order. I’ll explain: My program is generating HUGE matrices that always have their number of rows divisible by 3. The number of columns is always 3. I need to extract rows from these matrices in the following way: Let’s say I have a matrix 9x3:
1.1 1.2 1.3
2.1 2.2 2.3
3.1 3.2 3.3
4.1 4.2 4.3
5.1 5.2 5.3
6.1 6.2 6.3
7.1 7.2 7.3
8.1 8.2 8.3
9.1 9.2 9.3
I would like to end up with:
1.1 1.2 1.3
4.1 4.2 4.3
7.1 7.2 7.3
2.1 2.2 2.3
5.1 5.2 5.3
8.1 8.2 8.3
3.1 3.2 3.3
6.1 6.2 6.3
9.1 9.2 9.3
So basically it is taking these rows:
1:N/3:end
2:N/3:end
3:N/3:end
etc…….
Doing it with a ‘for’ loop is trivial but very time consuming. Is there an automatic way to do this? Thank you.
0 Comments
Accepted Answer
Andrei Bobrov
on 23 Jun 2012
one way
out = data(reshape(1:size(data,1),3,[])',:); %%%EDIT
second way
out = reshape(permute(reshape(data,3,[],3),[3 2 1]),3,[])';
ADD after Yair's answer
out = A(reshape(1:size(A,1),size(A,1)/3,[])',:);
ADD 2
[~,ii] = sort(rem(0:size(data,1)-1,size(data,1)/3)+1);
out = data(ii,:);
More Answers (4)
the cyclist
on 23 Jun 2012
I fear that I am misunderstanding the ordering when the number of rows is larger, but is this right?
out = data([1:3:end 2:3:end 3:3:end],:)
0 Comments
Jamie Rodgers
on 23 Jun 2012
MY Strategy: Generate required indices, and use arrayfun!
(i) Generate 2 matrices corresponding respectively to the row indices and column indices you want to see in the arranged data.
Columns index is easy as these don’t change, so its just numbers 1:3 in each row:
col_idx= repmat([1,2,3],size(unsorted,1),1);
We can rearrange rows according to your rules with repmat and using a combination of linear and row column indexing as follows:
row_idx=([1:3:size(unsorted,1);2:3:size(unsorted,1);3:3:size(unsorted,1)]');
row_idx=repmat(row_idx(:),1,size(unsorted,2));
(ii) Create a function handle to index into the original dataset
read_data=@(x,y)unsorted(x,y);
(iii) apply this using arrayfun:
sorted_data=arrayfun(read_data,row_idx,col_idx);
SHORTER ALTERNATIVE
harder to follow but does the same thing in exactly the same way
row_idx=([1:3:size(unsorted,1);2:3:size(unsorted,1);3:3:size(unsorted,1)]');
sorted =arrayfun(@(x,y)unsorted(x,y),repmat(row_idx(:),1,3),repmat([1:size(unsorted,2)],size(unsorted,1),1));
OR Just feed your data into the results into this function~
function [sorted] = sort_by_3s(unsorted) ;
row_idx=([1:3:size(unsorted,1);2:3:size(unsorted,1);3:3:size(unsorted,1)]') ;
sorted =arrayfun(@(x,y)unsorted(x,y),repmat(row_idx(:),1,3),repmat([1:size(unsorted,2)],size(unsorted,1),1));
2 Comments
Jamie Rodgers
on 23 Jun 2012
Just saw your second comment about wanting the transpose:
This is easy with my solution: Instead of generating a matrix of indices the same shape as unsorted (mx3), just generate the transpose shapes (3xm)... ofr any other shape you like for that matter... and apply the function in exactly the same way. Because the arrayfun operates elementwise, the output will be the same shape as the inputs, no matter what shape the unsorted matrix is.
As long as no value in the input matrices exceeds the matrix dimensions of the unsorted matrix, it will give you a result. You just have to make sure you are asking for the right rxc combinations in whatever matrix you input.
Walter Roberson
on 23 Jun 2012
Jamie, thank you for trying to format your code. Unfortunately the { and } character pair are not actually formatting characters and we don't know why they appear on the "Code" button. Two leading spaces is what is actually used for code formatting. I have adjusted your answer.
See Also
Categories
Find more on Resizing and Reshaping Matrices in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!