Is there a Matlab conditional IF operator that can be placed INLINE like VBA's IIF

37,918

Solution 1

There is no ternary operator in Matlab. You can, of course, write a function that would do it. For example, the following function works as iif with n-d input for the condition, and with numbers and cells for the outcomes a and b:

function out = iif(cond,a,b)
%IIF implements a ternary operator

% pre-assign out
out = repmat(b,size(cond));

out(cond) = a;

For a more advanced solution, there's a way to create an inline function that can even do elseif, as outlined in this blog post about anonymous function shenanigans:

iif  = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();

You use this function as

iif(condition_1,value_1,...,true,value_final)

where you replace the dots with any number of additional condition/value pairs.

The way this works is that it picks among the values the first one whose condition is true. 2*find(),1,'first') provides the index into the value arguments.

Solution 2

How about simply using the fact that MATLAB automatically converts variable types when required by the operation? E.g., logical to double.

If your variables are scalar double, your code, I believe, can be replaced by

a = b + (c > 0) * c;

In this case, the operator (c > 0) values 1 (logical type) whenever c > 0 and values to 0 otherwise.

Solution 3

Others have said already that there is no ternary ?: operator in Matlab. As a solution I suggest this function, which takes three functions instead of values. Therefore the amount of unnecessary calculations is minimized and you can check conditions before starting calculations, e.g. if a value is really numeric, or finite, or nonzero:

function [ out ] = iif( condition, thenF, elseF, in, out)
%iif Implements the ternary ?: operator
%   out = iif (@condition, @thenF, @elseF, in[, out])
%
%   The result is equivalent to:
%   condition(x) ? thenF(x) : elseF(x)
%
%   The optional argument out serves as a template, if the output type is
%   different from the input type, e.g. for mapping arrays to cells and
%   vice versa.
%
% This code is in the public domain.

mask = condition(in);
if nargin <= 4
  out = in;
end

if sum(mask)
  out(mask)  = thenF(in(mask));
end
if sum(~mask)
  out(~mask) = elseF(in(~mask));
end

end

Use it like this:

f = @(y)(iif(@(x)(x > 3), @(x)(x.^2), @(x)(x/2), y))
f(linspace(0,6,10))

Solution 4

There is no built-in solution for this, but you can write an IIF yourself.

function result=iif(cond, t, f)
%IIF - Conditional function that returns T or F, depending of condition COND
%
%  Detailed 
%     Conditional matrix or scalar double function that returns a matrix
%     of same size than COND, with T or F depending of COND boolean evaluation
%     if T or/and F has the same dimensions than COND, it uses the corresponding 
%     element in the assignment
%     if COND is scalar, returns T or F in according with COND evaluation, 
%     even if T or F is matrices like char array.
%
%  Syntax
%    Result = iif(COND, T, F)
%           COND - Matrix or scalar condition
%           T  - expression if COND is true
%           F  - expression if COND is false
%           Result - Matrix or scalar of same dimensions than COND, containing
%                    T if COND element is true or F if COND element is false.
%
if isscalar(cond) 
   if cond 
       result = t;
   else
       result = f;
   end
else
  result = (cond).*t + (~cond).*f;
end  
end

Solution 5

Inspired by Jonas' answer the function below also works for mixed type input and chars, for which his function isn't stable.

function out = iif(cond, a, b)
%IIF implements a ternary operator

    % Use cell output for either char or mixed type input
    if ischar(a) || ischar(b) || ~strcmp(class(a), class(b))
        out = cell(size(cond));
        [out{cond}] = deal(a);
        [out{~cond}] = deal(b);
    else
        % Use array output and logical indexing
        out = repmat(b, size(cond));
        out(cond) = a;
    end
end

Edit: weeded out the extra conditional options in the cell branch, which were apparently remnants of a previous mistake, this is probably faster, and definitely cleaner.

Share:
37,918

Related videos on Youtube

Lance Roberts
Author by

Lance Roberts

Control Systems Engineer. Most people want to stick their head in the sand and ignore problems, in an effort to avoid conflict. I refuse to be that passive person. Problems are there to be fixed, which means that first they have to identified. Denial is not just a river in Egypt.

Updated on October 08, 2020

Comments

  • Lance Roberts
    Lance Roberts over 3 years

    In VBA I can do the following:

    A = B + IIF(C>0, C, 0)
    

    so that if C>0 I get A=B+C and C<=0 I get A=B

    Is there an operator or function that will let me do these conditionals inline in MATLAB code?

    • Tim Williams
      Tim Williams over 11 years
      possible duplicate of Matlab conditional assignment
    • Lance Roberts
      Lance Roberts over 11 years
      @Tim Williams, No, I'm looking for INLINE.
    • Jonas
      Jonas over 11 years
      Have a look at this blog post that shows how to create an inline function for iff
    • Lance Roberts
      Lance Roberts over 11 years
      @Jonas, that worked great if you want to write up an answer with the link and an excerpt of the basics I'll upvote and accept it.
    • Jonas
      Jonas over 11 years
      @LanceRoberts: I have created the answer
    • Sanjay Manohar
      Sanjay Manohar over 10 years
      For an extension of @Alex's answer, see stackoverflow.com/a/15870464/93910
  • Jonas
    Jonas over 11 years
    @EitanT: Yes, this works indeed well when you can multiply (though you may want to use parentheses around ~cond). However, the other answer already mentioned it, so I though I'd not repeat the other answer.
  • masterxilo
    masterxilo over 10 years
    This is the best approximation to a C ?: which will not evaluate the branch that is not taken. Unfortunately the syntax is meh.
  • Wauzl
    Wauzl over 9 years
    You could even use this do define iif = @(c,t,f) c.*(t-f) + f, so you can even do things vectorised. I think your answer is the best MATLAB-solution for simple uses.
  • Ben Voigt
    Ben Voigt almost 8 years
    Vector version doesn't handle NaN properly
  • Cris Luengo
    Cris Luengo about 5 years
    This does not answer the question. Please take the tour before contributing to this site. Thanks!
  • Cris Luengo
    Cris Luengo over 3 years
    The first method works only in Octave, it is not legal MATLAB syntax.
  • vitaminace33
    vitaminace33 over 3 years
    It is. Here an official example: Content Indexing with Curly Braces, {}. mathworks.com/help/matlab/matlab_prog/…
  • Cris Luengo
    Cris Luengo over 3 years
    You can do tern = {F,T}; tern = tern{bool+1}, but you can’t do tern = {F,T}{bool+1}.
  • vitaminace33
    vitaminace33 over 3 years
    I see, I stand corrected. I will edit the answer to incorporate this.