Home > Back-end >  Distribute elements of an array to different variables in Matlab
Distribute elements of an array to different variables in Matlab

Time:11-23

I see equivalent operations being done several times in my Matlab code, and I think, there must be a way to condense these and do it all once. In this case it was checking whether some variables were less than a certain epsilon:

if abs(beta) < tol
    beta = 0;
end
if abs(alpha) < tol
    alpha = 0;
end
if abs(gamma) < tol
    gamma = 0;
end

I tried combining these into a few lines that deal with the whole boodle,

overTol = [alpha,beta,gamma] >= tol;
[alpha,beta,gamma] = [alpha,beta,gamma] .* overTol;

If this was Python, where a list is a list is a list, that would be fine, but in Matlab, an operation on the right produces one variable on the left except in special situations.

After reading Define multiple variables at the same time in MATLAB? and Declare & initialize variables in one line in MATLAB without using an array or vector, I tried using deal, but [alpha,beta,gamma] = deal([alpha,beta,gamma] .* overTol); does not distribute the terms of the vector given to the deal function between the terms in the vector on the left, but instead gives a copy of the whole vector to each of the terms.

The last thing I want to do is set the right equal to a unique vector and then set alpha, beta, and gamma equal to the terms of that vector, one by one. That's just as ugly as what I started with.

Is there an elegant solution to this?

CodePudding user response:

Ok, the comments explain why there are probably better approaches. I was curious if it could be done. It can, but maybe it shouldn't be.

% Initial values
a = 0.01; b = 0.1; c = 1; 
% Tolerance
tol = 0.05;
% Function - note returns a scalar cell
f = @(f) {f.*(abs(f)>tol)}
% arrayfun returns a cell of the new values
% cell2struct turns that into a struct array with a single field 'f'
% the trailing dot-reference extracts that field and builds a 
% comma-separated list which can be used to assign the new values
[a2,b2,c2] =  cell2struct(arrayfun(f, [a,b,c]),{'f'}).f

CodePudding user response:

You could use cellfun to generate a cell array of results, and deal to redistribute it back into variables

f = @(x) x.*(abs(x)>tol);             % function which returns x, or x if abs(x)<tol
d = cellfun( f, {a,b,c}, 'uni', 0 );  % apply function to inputs a,b,c
[a,b,c] = deal(d{:});                 % deal results back to a,b,c

A more readable (and maintenance-friendly) method might be to just use functions and accept that it's going to use more lines. Line count is not the enemy...

a = applyTol(a);
b = applyTol(b);
c = applyTol(c);

function x = applyTol( x )
    tol = 0.5;
    if abs(x) < tol
        x = 0;
    end
end 
  • Related