'Is Ternary operation valid in Octave?
Question is ternary operation valid as i am not able to find any document related to it online. And i also find out that ternary is not possible in MATLAB so any suggestion and answers will be appreciated here.
#Code with ternary operation
taxes = (income > 50000)*(((income-50000) * 0.20)+(0.10*50000)) + (~(income > 50000))*0.10 *50000
#Condition True and this computation False then this computation
#Code with if and else
if (income) > 50000
#income = income - 50000
#Taxed at 10% (i.e 0.10) for $ 50000
#taxes = 50000 * 0.10
#Rest income will be Taxed at 20% (i.e 0.20)
taxes = 50000 * 0.10 + ((income-50000) * 0.20)
else
#Taxed at 10% (i.e 0.10)
taxes = income * 0.10
endif
Output:
GNU Octave, version 6.1.0
Copyright (C) 2020 The Octave Project Developers.
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. For details, type 'warranty'.
Octave was configured for "x86_64-w64-mingw32".
Additional information about Octave is available at https://www.octave.org.
Please contribute if you find this software useful.
For more information, visit https://www.octave.org/get-involved.html
Read https://www.octave.org/bugs.html to learn how to submit bug reports.
For information about changes from previous versions, type 'news'.
>> income = 60000;
>> compute_taxes
taxes = 7000
>> income = 50000;
>> compute_taxes
taxes = 5000
>>
Solution 1:[1]
There are a few important differences between any definition of a ternary operator in any language, and an if statement.
The main one is that the latter is a statement, whereas a ternary operator is by definition an expression. In other words, you expect it to return a value. An if block in octave/matlab does not "return" a value (i.e. you can't do a = if ... endif
). If you need something 'returned', you need to assign it to an external variable inside the loop, and then use that variable outside the loop.
The second big thing, is that a ternary operator should be chainable. Ie you should be able to do "if this, then that, otherwise if that then that other thing", such that at the end of a long chain of comparisons you return a single value.
Now, octave and matlab do not have this kind of operator. But in octave, it's easy enough to simulate one, e.g. with cells:
M1 = false; M2 = false; M3 = true;
{'expression1', 'expression2', 'expression3', 'fallback'}([ M1, M2, M3, true ]){1}
If you really want to, you can make that kind of thing into a nice anonymous function, which returns the first expression for which its mask/test was true:
tern = @(varargin) reshape(varargin,2,[])(2,:)([reshape(varargin,2,[]){1,:}]){1}
tern( M1, 1, M2, 2, M3, 3, true, 4 ) % ans = 3
where 'fallback' is achieved simply by having a test that evaluates to 'true' explicitly before the 'fallback' value.
Note: This style of 'chaining' two or more indexing operations inside an anonymous function only works in octave, as unfortunately matlab does not allow chained operations, e.g. a(1)(2)
. There is nothing stopping you from making an equivalent 'proper', external function though, where you save intermediate results to a temporary variable before indexing it a second time; therefore, conceptually, this strategy will also work in matlab.
Alternatively, you could make a simpler 'ternary operator' (well, function) using a slightly different syntax, where you pass a 'tests/masks' array, and 'expressions', and 'fallback' cells separately. E.g.
tern2 = @(M,E,F) [E, F]{find([M, true], 1)}
tern2( [M1, M2, M3], {1, 2, 3}, {4} ) % ans = 3
Finally, there is also the ifelse
function, which is similar in spirit, i.e. ifelse(test, expr_if_true, expr_if_false)
, but this is not really a true ternary operator/function, since it is not chainable; it's more useful for choosing between two alternatives based on a 'true/false mask', e.g.
ifelse( [M1, M2, M3], {1, 2, 3}, {4,5,6} )
% ans = { 4, 5, 3 }
Solution 2:[2]
You can simulate ternary if
operator with two short circuit &&
and ||
operators.
Consider this if/else
statement:
if condition
val = expr1;
else
val = expr2;
end
Define t
as t = @(x) 1;
and the ternary if
operator as:
condition && t(val = expr1) || t(val = expr2);
An important point in implementing the ternary if
operator is the evaluation of expressions expr1
and expr2
. If condition
is true
then expr2
must not be evaluated and if condition
is false
then expr1
must not be evaluated. In the functions like ifelse/merge
both expressions are evaluated before they are passed to the function so ifelse
shouldn't be considered as a true ternary if
operator.
There are some MATLAB based implementations here and here that are used to create recursive anonymous function. The trick is that the expressions are wrapped by a lambda to prevent their evaluation.
Consider the following function that computes the nth Fibonacci number:
function val = fib(f, n)
if n <= 2
val = 1;
else
val = f(f, n - 1) + f(f, n - 2));
end
The current proposed technique can be used to implement it as (tested on Octave 6.1.0):
fib = @(f, n, t = @(x) 1, tmp = n <= 2 && t(val = 1) || t(val = f(f, n - 1) + f(f, n - 2))) val;
In situations other than recursive anonymous function you can use this:
val = {condition && t(tmp = expr1) || t(tmp = expr2), tmp}{2};
However those tricks may not perform better than if/else
statement.
Solution 3:[3]
Consider implementing a ternary conditional operator function
Don't know if the matlab version can handle strings, and arrays as this can
clear ternary
function tern = ternary( test, alternatives);
if length( alternatives(:,1)) == 1,, alternatives = alternatives(:); end;
if test,, tern = alternatives(1,:);
else, tern = alternatives(2,:); end
return; end;
some sample calls
methodss = ['Runge-Kutta'; 'Adams-MLS'];
adaptive_step = ['adaptive step control'; 'fixed step size'];
report_method = @(selectmethod) [char( ternary (selectmethod(1), methodss )) ' ' ...
char( ternary (selectmethod(2), adaptive_step)) ];
%
report_method( [true false]),; % self-starting = true ; adaptive step size = false
report_method( [false true ]),; % self-starting = false; adaptive step size = true
% ans = Runge-Kutta fixed step size
% ans = Adams-MLS adaptive step control
ternary(2 > 2, [123 456]) % 456
ternary(2 >= 2, [123 456]) % 123
ternary(2 > 2, [123 456; 789 999]) % 789 999
ternary(2 >= 2, [123 456; 789 999]) % 123 456
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Donovan Roisin |