ternary operator in matlab
Asked Answered
M

13

53

is there a way of typing for if like:

var = (cond) ? true : false;

or do we have to use this format?

if (cond)
 true
else
 false
end
Mackenie answered 8/4, 2011 at 12:18 Comment(1)
But for a more general case, see some of the answers here: #27562381Tegan
M
40

MatLab doesn't have a ternary operator, or any other syntactic sugar for one-line if-statements. But if your if-statement is really simple, you could just write it in one line anyway:

if (cond); casetrue(); else; casefalse(); end

It's not as simple as ternary operator, but still better than writing it in 5 lines of code.

Mechling answered 19/12, 2014 at 22:2 Comment(1)
Hoever simple, if/switch/loop statements aren't supported in lambda/anonymous function definitions in Matlab.Sepsis
P
21

Hmm... no one has mentioned this

fi = @(varargin)varargin{end-varargin{1}}

somewhere in the docs it is written the `end' is coming to one so this will be more future proof

fi = @(varargin)varargin{length(varargin)-varargin{1}}

Usage :

fi(input('Do you like Matlab ? '),'yes','no')
>> no

If your in the need of inline cases see Mathworks ...

Plywood answered 27/8, 2015 at 15:24 Comment(2)
This is probably the ugliest and hardest to understand piece of Matlab code I've seen. Usage is easy though, yay!Belly
Note that, unlike an if, both sides are evaluated. Also, this assumes that your first argument is logical (aka Boolean). Whereas an if will consider 3 to be true, this method will see 3 as false. You can simulate how if works using fi = @(varargin) varargin{length(varargin) - logical(varargin{1})};. If your input is a matrix, you can use fi = @(varargin) varargin{length(varargin) - all(logical(varargin{1}), "all")};.Handle
C
13

If you only need true or false, you can do what MatlabSorter suggests. In case you want a real tertiary operator (i.e. a = b ? c : d), there is none in MATLAB. However, using the file supplied here, you can get close.

Command answered 8/4, 2011 at 12:24 Comment(0)
E
12

You can do

var = 5 > 4;

which will set var to true. Just substitute what ever you need for 5 > 4.

Epiphysis answered 8/4, 2011 at 12:21 Comment(2)
Na, you can use (a > b) as a factor and then add another product with the opposite statement : var = (a < 0) * (-a) + (a >= 0) * (a)Fancier
If we need to use the ternary operator inside disp or fprintf?Yester
H
10

MATLAB doesn't have conditional expressions, but in some situations you can get a similar effect by saying, e.g., var = cond*true_expr + (1-cond)*false_expr. Unlike C's conditional expression, this will of course always evaluate both true_expr and false_expr, and if cond happens not to be either 0 or 1 (note: false behaves like 0; true behaves like 1) you'll get crazy results.

Halftrack answered 8/4, 2011 at 12:27 Comment(3)
It should be possible to create a function which takes a condition and two function handles. Then you have the wanted shortcut behaviour.Schramm
Elegant but works only for numerical expressions, I tried it with strings and it returned them as an ASCII values arrayPerlite
This also does not work if true_expr or false_expr are infProtestant
J
6

The following solution has two major advantages over the solutions proposed so far:

  1. It supports lazy evaluation, i.e. only the selected input is evaluated.
  2. Unlike a if/else statement packed in one line, it can also be used in anonymous functions.
function out = tern(cond, resTrue, resFalse)

if cond
    res = resTrue;
else
    res = resFalse;
end 
out = res();  %<--- The trick!

The trick to achieve lazy evaluation is that the last line in tern evaluates the selected result. This way, you can pass anonymous functions to tern and only the selected will be invoked.

E.g. the following can be invoked without error, when the file with fileName is not existing:

x = tern( isfile( fileName), @()load( fileName ), ones(10 ));

It should be noted that, when res is not a anonymous function but of a different basic type (e.g. numeric, character, cell ) in the last line, res() evaluates to res itself.

So in summary, the only little difference to a real ternary operator is that it is required to add @() to the arguments that should only be conditionally evaluated.

Jacquard answered 17/9, 2022 at 0:55 Comment(3)
shouldn't the third parameter be "@()ones(10)" ?Astronomer
This is also an option to save execution time for "ones(10)". However, it would not fail with "ones(10)".Jacquard
Great hack, I'd not realize ones(10) simply works without having to check it's a lambdaCostive
B
4

Quick and elegant. I would simply write tern( a>b, a, b) Downside is you have to copy paste everywhere, or have and extra file in the directory

function b = tern(cond, a, b)
    if cond
        b=a;
    end
end
Bolshevist answered 31/8, 2020 at 4:45 Comment(1)
beware that this does not work if you need lazy evaluation, e.g. b always evaluates regardless of cond (might seem obvious, but you probably just think abstract: 'Ah ternary operator here we go' and use it as normal, things might break for you)...Cambrel
K
3

Replace

c = (x ? a : b)

by

c = subsref({b; a}, substruct('{}', {x + 1}))

x should be a boolean value or 1 or 0.
true or 1 will select a
false or 0 will select b
This should work with all what cells can contain and can also be used in an intricate formular!

Kernite answered 6/11, 2018 at 14:19 Comment(1)
Note: a and b are both evaluated. This may be a difference to if ... else ... end.Kernite
V
3

@Leonid Beschastny is correct about the inlining the if-else-end statement, but If one must, then with any assignment value that can be evaluated as boolean, one can the shortcut boolean operators || and &&:

(cond) && ((var=true_val)||1) || (var=false_val);

Rules:

  1. shortcut boolean ops || and && must be used, NOT | or &
  2. will work with boolean, numeric and char assignments
  3. will NOT work with cell array or function handles
  4. the assignments must be wrapped in parenthesis.
  5. (var=true_val) must be followed by ||1 in case true_val == false
  6. true and false assignments may be to different variables (i.e. (var1=true_val) while (var2=false_val))
  7. true_val and false_val can be different types provided each then can be evaluated as boolean

Alternatively one can do this:

cond && (func1(..)||1) || func2(...);

provided func1 and func2 return a boolean testable value including nothing at all (but no cell arrays!):

Viniculture answered 5/12, 2019 at 9:2 Comment(1)
For which Matlab version is this? I have R2018a and the assignment var=true_val does not work. Matlab reports a syntax error.Rawalpindi
U
2

I use this style frequently:

cond = what < ever;

n = getfield([23,42], {1+(what < ever)}) % for any 1x1-data
s = cell2mat(getfield({'no','yes'}, {1+(what < ever)})) % for nonuniform

it's compact enough to not require a helper function

Urial answered 27/10, 2017 at 9:31 Comment(0)
U
1

I know this is late, but for people trying to find an answer I came up with this.

If you want a boolean var = (cond) ? true : false; you can just do:

var = cond;

If you want a number var = (cond) ? value_if_true: value_if_false; then do:

var = cond*value_if_true + ~cond*value_if_false;

This is all using that matlab treats true as 1 and false as 0. Therefore that's why the first statement expanded really is

var = cond*1+ ~cond*0;

If you want a text var = (cond) ? text_if_true: text_if_false; then do:

[repmat(text_if_true,1,cond) repmat(text_if_false,1,~cond)];

Unfortunately you can't mix numerical values with text using this method, just write it with an if-else-end statement.

Unless answered 29/4, 2022 at 12:51 Comment(0)
C
0

I found this question when I needed to set my matrix values to 0 or 1 based on an arbitrary condition (e.g. element value is greater than pi). Turns out it's as easy as:

M > pi

Sure it's less generic than the original question but this corner case may help someone.

Cowskin answered 2/2, 2023 at 21:21 Comment(0)
T
0

If anyone is looking for a vectorized ternary (operating on logical arrays and number arrays), here's a really simple one (it is not short-circuiting):

vectorizedTernary = @(cond, resTrue, resFalse) cond.*resTrue + (1-cond).*resFalse
vectorizedTernary([0 1 1 0 0], 1:5, 5:-1:1) % ans = [5 2 3 2 1]

Because I used 1-cond instead of ~cond, you can even use it with non-logical conditions, like probabilities:

vectorizedTernary([.2 .7 1], [.1 .2 .3], [0 1/3 2/3]) % ans = [.02 .24 .3]
Thay answered 15/1, 2024 at 12:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.