3

I have an array A, and want to reshape the last four elements of each column into a 2x2 matrix. I would like the results to be stored in a cell array B.

For example, given:

A = [1:6; 3:8; 5:10]';

I would like B to contain three 2x2 arrays, such that:

B{1} = [3, 5; 4, 6];
B{2} = [5, 7; 6, 8];
B{3} = [7, 9; 8, 10];

I can obviously do this in a for loop using something like reshape(A(end-3:end, ii), 2, 2) and looping over ii. Can anyone propose a vectorized method, perhaps using something similar to cellfun that can apply an operation repeatedly to columns of an array?

carandraug
  • 12,938
  • 1
  • 26
  • 38
nicktruesdale
  • 815
  • 5
  • 12
  • I'm not sure you need to do any reshaping to achieve the result you want. Why not use `for i = 1:3`: `B{i} = A((2*i-1):2*i, 2:3);`? Do you have a performance problem which is prompting the need for 'vectorization'? – Brian L Nov 27 '12 at 03:01
  • Ah, I see I picked a confusing example. I am taking the last four elements of a column, not already-square subsets of A. Also, this simple example does not need extra performance - I intent to extend it to create 18x18 arrays from a lot of ode45 data. Which, technically, also doesn't need it; I was mostly curious for future reference. – nicktruesdale Nov 27 '12 at 03:30
  • 1
    Just for the record, [loops are typically faster than cellfun](http://stackoverflow.com/questions/12522888/arrayfun-can-be-significantly-slower-than-an-explicit-loop-in-matlab-why) – Colin T Bowers Nov 27 '12 at 06:06

1 Answers1

2

The way I do this is to look at the desired indices and then figure out a way to generate them, usually using some form of repmat. For example, if you want the last 4 items in each column, the (absolute) indices into A are going to be 3,4,5,6, then add the number of rows to that to move to the next column to get 9,10,11,12 and so on. So the problem becomes generating that matrix in terms of your number of rows, number of columns, and the number of elements you want from each column (I'll call it n, in your case n=4).

octave:1>  A = [1:6; 3:8; 5:10]'
A =

    1    3    5
    2    4    6
    3    5    7
    4    6    8
    5    7    9
    6    8   10

octave:2>  dim=size(A)
dim =

   6   3

octave:3> n=4
n =  4
octave:4> x=repmat((dim(1)-n+1):dim(1),[dim(2),1])'
x =

   3   3   3
   4   4   4
   5   5   5
   6   6   6

octave:5> y=repmat((0:(dim(2)-1)),[n,1])
y =

   0   1   2
   0   1   2
   0   1   2
   0   1   2

octave:6> ii=x+dim(1)*y
ii =

    3    9   15
    4   10   16
    5   11   17
    6   12   18

octave:7> A(ii)
ans =

    3    5    7
    4    6    8
    5    7    9
    6    8   10

octave:8> B=reshape(A(ii),sqrt(n),sqrt(n),dim(2))
B =

ans(:,:,1) =

   3   5
   4   6

ans(:,:,2) =

   5   7
   6   8

ans(:,:,3) =

    7    9
    8   10

Depending on how you generate x and y, you can even do away with the multiplication, but I'll leave that to you. :D

IMO you don't need a cell array to store them either, a 3D matrix works just as well and you index into it the same way (but don't forget to squeeze it before you use it).

I gave a similar answer in this question.

Community
  • 1
  • 1
engineerC
  • 2,808
  • 17
  • 31