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

后端 未结 10 1176
滥情空心
滥情空心 2020-12-01 11:06

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

相关标签:
10条回答
  • 2020-12-01 11:23

    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.

    0 讨论(0)
  • 2020-12-01 11:23

    What you refer to is a ternary operator, in C-like notation, ?:. The expression

    tern = bool ? T : F
    

    returns T if bool evaluates to true, F otherwise. MATLAB has no ternary operator, however it can be implemented in different ways as an inline expression.

    Arrays

    % cell array version (any type)
    tern = {F,T}{bool+1} % only Octave
    tern = subsref({F,T}, struct('type', '{}', 'subs', {{bool+1}}))
    % vector array version (numeric types only)
    tern = [F,T](bool+1) % only Octave
    tern = subsref([F,T], struct('type', '()', 'subs', {{bool+1}}))
    

    Note that T and F have been swapped, and that different brackets are used. The vector array version is a specialization for numeric types. MATLAB does not allow direct indexation of fresh arrays, hence the use of subsref.

    • Pros: Works for any type and any value. Can be used inline.
    • Cons: Before returning the result to tern, both T and F are evaluated.

    Logical operators and eval

    ( bool && eval('tern=T') ) || eval('tern=F')
    

    Note that the logical operators are short-circuited.

    • Pros: Works for any type and any value. Only one, T or F, is evaluated.
    • Cons: Works only in Octave. Can't be used inline, but through the variable tern. eval is not efficient but required.

    Basic arithmetic

    tern = bool*T + !bool*F
    
    • Pros: Can be used inline.
    • Cons: Works only for numeric types, and might fail when T or F are NaN or Inf. Both, T and F, are evaluated.

    Maximum

    tern = max(T,F) % bool = T>F
    

    Note that this solution fits the particular requirements of the initial question with max(C,0).

    • Pros: Can be used inline.
    • Cons: Works only for numeric types, and might fail when T or F are NaN. Both, T and F, are evaluated. Use is strongly limited.
    0 讨论(0)
  • 2020-12-01 11:33

    If you're looking for an option that doesn't force you to build a function and can take care fairly simple expressions, you can take advantage of anonymous functions. The anonymous function returns a logical, which can be a numeral 1 or 0. Because of this, they can be used to multiply with other numbers to determine if they still hold a value after the expression, or lose their value.

    For your case (including if A, B, and C are vectors or not): A = B .+ (@() C>0)()

    0 讨论(0)
  • 2020-12-01 11:34

    This is more of an addenum to Alex's answer.

    Alex's method doesn't work when you want to return inf

    In these cases you often end up getting a 0*inf figure, which MATLAB will evaluate to NaN. Problematic... We can avoid this multiplication using a lookup instead.

    As an example, a useful barrier function in convex optimization is something that behaves like log everywhere positive, and -inf elsewhere. Here is how you might create such a function using a lookup:

    INF_CONDITION = [0, inf];
    fn_logbr = @(x) (x>0)*log(x) - INF_CONDITION( 1+(x<=0) )
    

    Inline conditionals are a hack, and you lose lazy evaluation. You have to be careful. However, having semantic code is really nice, and its easier to share your code when you can't guarantee everyone's environments are the same.

    0 讨论(0)
提交回复
热议问题