필터 지우기
필터 지우기

how to access cells of n-dimensional array without colon operator?

조회 수: 1 (최근 30일)
I need to develop a function that can accept any n-dimensional arrays. It should access cells of the arrays in the following way:
mat(1:end-1, :, :, ... :);
mat( :, 1:end-1, :, ... :);
mat( :, :, 1:end-1, ... :);
mat( :, :, :, ... 1:end-1);
And also by other similar combinations for more then one dimension, e.g.:
mat(1:end-1, :, 1:end-1, ... :);
How can it be done in a smarter way, so I do not need to consider all cases manually, and it can be universal for any number of dimensions?
I was looking for something as:
new_mat = function(mat, (vector with dimensions to be used), (vectors used to access cells, e.g., 1:end-1));
For example it could be:
new_mat = function(mat, [1 3], [1:end-1; 2:end]);
which is equivalent to:
new_mat = mat(1:end-1, :, 1:end-1, ... :);
GREAT THANKS!

채택된 답변

Sean de Wolski
Sean de Wolski 2013년 9월 17일
편집: Sean de Wolski 2013년 9월 17일
That was a fun post-lunch challenge, thanks!
extractFromND(magic(3),[1 2],[2 3;3 3])
It does not accept end you have to pass in the calculation yourself, e.g.
size(x,4)-1 %equivalen to end-1 in dim 4
The function
function Mextract = extractFromND(M,dim,datarange)
% EXTRACTFROMND extract data range in dim from M
%
%Usage:
% -Mextract = extractFromND(M,dim,datarange);
%
%Inputs:
% -M: nd matrix
% -dim: dimensions that the rows of datarange use
% -datarange: [dim x 2] where each row is the range in low/high in dim
%
%Outputs:
% -MExtract: M not including data outside of datarange in dim of M
%
%
%Examples:
%
% x = ones(3,3,3,3,3);
% x2 = extractFromND(x,[1 5],[2 3;1 2]);
% size(x2);
%
%See Also: colon
%
%
%TODO: make datarange nx3 with middle column the stride
%
%
% Copyright 2013 The MathWorks, Inc.
% SCd 735494
%
%Rudimentary error checking
assert(nargin==3,'Exactly three inputs expected');
ndM = ndims(M);
assert(max(dim)<=ndM,'Can''t pull from more dimensons than we have');
ned = numel(dim); %numel extract dimensions
assert(size(datarange,1)==ned,'datarange should have the same number of rows as dim');
szM = size(M);
assert(all(szM(dim).'>=datarange(:,2)),'out of range datarange');
%Engine:
%Build index vector
idx = repmat({':'},1,ndM);
for ii = 1:ned
idx{dim(ii)} = datarange(ii,1):datarange(ii,2);
end
%Extract from M:
Mextract = M(idx{:});
end

추가 답변 (4개)

Jim Hokanson
Jim Hokanson 2013년 9월 17일
Unfortunately I don't know of any way of doing 'end' as a variable, but the basic gist is something like the following:
indices = cell(1,ndims(mat));
indices(:) = {':'} %This is a bit of magic ...
%At this point you have specified you want all values from all dimensions
%Now limit the variables obtained in specific dimensions
dims_change = [1 3];
grab_range = [1 1; 2 0]; %i.e. now mat(1:end-1,:,2:end-0,... etc)
for iDim = 1:length(dims_change)
cur_dim = dims_change(iDim);
cur_start = grab_range(iDim,1);
samples_remove_end = grab_range(iDim,2);
dim_size = size(mat,cur_dim);
indices(cur_dim) = {cur_start:(dim_size-samples_remove_end)};
end
%Now, use cell array expansion where each element gets treated as a different input
new_mat = mat(indices{:});

Matt J
Matt J 2013년 9월 17일
편집: Matt J 2013년 9월 18일
Here is an object-oriented approach (see the classdef below). It might be less intuitive than what you had in mind. However, it lets you use indexing expressions with all normal flexibility (including "end"), but omitting the colons as you wished. It also avoids the drawbacks of my earlier Answer, which required EVAL.
Example:
Given A=rand(5,4,3,6), the following
obj=myclass(A);
B=obj{[1,4]}(2:end-1,3:end-2);
is equivalent to B=A(2:end-1,:,:,3:end-2).
classdef myclass
properties
data;
subset;
end
methods
function obj=myclass(A,subset)
if nargin<2, subset=1:ndims(A); end
obj.data=A;
obj.subset=subset;
end
function out=end(obj,k,~)
out=size(obj.data,obj.subset(k));
end
function B=subsref(obj,S)
if isequal(S(1).type,'{}')
obj.subset=S(1).subs{1};
S(1)=[];
end
if isempty(S), B=obj; return; end
nn=max([ndims(obj.data),obj.subset]);
idx=repmat({':'},1,nn);
idx(obj.subset)=S.subs;
B=obj.data(idx{:});
end
function N=numel(obj,varargin)
N=1;
end
end
end

Matt J
Matt J 2013년 9월 17일
편집: Matt J 2013년 9월 17일
function B=myaccess(A,subset,varargin)
%Example:
%
% B=myaccess(A,[1,2],'2:end-1','3'),
%
%is equivalent to B=A(2:end-1,3,:)
m=length(subset);
n=ndims(A);
sz=size(A);
idx=repmat({':'},1,n);
for ii=1:m
jj=subset(ii);
r=1:sz(jj);
idx{jj}=eval(['r(' varargin{ii} ')']);
end
B=A(idx{:});
  댓글 수: 3
Sean de Wolski
Sean de Wolski 2013년 9월 17일
If I was going to use this, I would say that the eval is not worth it, pass in the size(x,dim)-x calculation.
Matt J
Matt J 2013년 9월 17일
Not sure what "size(x,dim)-x" corresponds too. The result of that expression would be an array of size(x).
I think you mean you want to resolve all "end" expressions prior to the function call using size(x,dim), but this would require a loop over dim that is almost as much code as the functions we've all proposed.
Also, both you and Jim proposed a solution that would work for contiguous ranges a:b, but note that the OP never specified that the ranges to be indexed were contiguous. A modification of my code that might be more appealing is
for ii=1:m
jj=subset(ii);
r=1:sz(jj);
if ischar(varargin{ii}) %support "end" expressions
idx{jj}=eval(['r(' varargin{ii} ')']);
elseif isnumeric(varargin{ii})
idx{jj}=varargin{ii};
end
end

댓글을 달려면 로그인하십시오.


Tomasz
Tomasz 2013년 9월 18일
편집: Tomasz 2013년 9월 18일
Thank you for extremely fast response and good solutions! I have used this forum for the first time, and I am very positively surprised. Tomasz

카테고리

Help CenterFile Exchange에서 Operators and Elementary Operations에 대해 자세히 알아보기

제품

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by