问题描述:

I have matrices:

a= 0.8147 0.1270 0.6324

0.9058 0.9134 0.0975

b= 0.2785 0.9649 0.9572

0.5469 0.1576 0.4854

0.9575 0.9706 0.8003

c = 0.1419 0.7922

0.4218 0.9595

0.9157 0.6557

and also I have another matrix

 I= 1 3 1 1

2 1 3 2

I want to get d matrix such that

d= a(1,3) b(3,1) c(1,1)

a(2,1) b(1,3) c(3,2)

where indices come as two consecutive entries of I matrix.

This is one example I get. However, I get different size matrices for a,b,c,.. and I.

Added: I is m x (n+3) which includes indices, and other (n+2) matrices which have corresponding entries are X,A1,A2,...,An,Y. When n is given, A1,A2,...,An matrices are generated.

Can someone please help me to write Matlab code for this task?

网友答案:

You can do it with varargin. Assuming that your matrices are constructed such that you can form your desired output in the way you want (Updated according to Carmine's answer):

function out = IDcombiner(I, varargin)
out = zeros(size(I, 1), nargin-1);
idx = @(m, I, ii) (sub2ind(size(m), I(:, ii), I(:, ii+1)));
for ii = 1:1:nargin-1
    out(:, ii) = varargin{ii}(idx(varargin{ii}, I, ii));
end

Now using this function you can make your selection on a flexible number of inputs:

out = IDcombiner(I, a, b, c)

out =

    0.6324    0.9575    0.1419
    0.9058    0.9572    0.6557

There is also a one-liner solution, which I do not recommend, since it dramatically decreases the readability of the code and doesn't help you gain much:

IDcombiner = @(I,varargin) ...
    cell2mat(arrayfun(@(x) varargin{x}(sub2ind(size(varargin{x}), ...
    I(:,x), I(:,x+1))), 1:nargin-1, 'UniformOutput', false));
网友答案:

Normally a matrix is not interpreted as a list of indices, but you can have this if you use sub2ind. To use it you need the size of the matrix you are addressing. Let's make an example starting with a:

a(sub2ind(size(a), I(:,1), I(:,2)))

The code does not change if you first assign the newly generated matrices to a variable name.

will use the column I(:,1) as rows and I(:,2) as columns.

To make the code more readable you can define an anonymous function that does this, let's call it idx:

idx = @(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))

So finally the code will be

d = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3))]

The code does not change if you first assign the newly generated matrices to a variable name.

Other details

Let's make an example with 2 central matrices:

a = rand(3,1)   % 3 rows, 1 column
b = rand(3,3)   % 3 rows, 3 columns
c = rand(3,3)   % another squared matrix
d = rand(3,1)   % 3 rows, 1 column

The definition of the anonymous function is the same, you just change the definition of the output vector:

output = [a(idx(a,I,1)), b(idx(b,I,2)), c(idx(c,I,3)), d(idx(d,I,3))]

Keep in mind that following that pattern you always need a I matrix with (n_matrices + 1) columns.

Generalization

Let's generalize this code for a number n of central matrices of size rxr and for "side matrices" of size rxc. I will use some values of those parameters for this example, but you can use what you want.

Let me generate an example to use:

r = 3;
c = 4;
n = 3;

a = rand(r,c);   % 2D array
b = rand(r,r,n); % 3D array, along z = 1:n you have 2D matrices of size rxr
c = rand(r,c); 

I =  [1 3 1 2 1 3; 2 1 3 1 1 1];

The code I wrote can easily be extended using cat to append matrices (note the 2 in the function tells MATLAB to append on the direction of the columns) and a for cycle:

idx = @(m,I,i)(sub2ind(size(m), I(:,i), I(:,i+1)))

d = a(idx(a,I,1));
for i = 1:n
    temp = b(:,:,i);
    d = cat(2,d,temp(idx(tmp,I,i+1)));
end
d = cat(2,d,c(idx(c,I,n+1)));

If you really don't want to address anything "by hand", you can use cell arrays to put all the matrices together and then cyclically apply the anonymous function to each matrix in the cell array.

相关阅读:
Top