Existe-t-il un opérateur MATLAB conditionnel IF qui peut être placé en ligne comme IIF de VBA

Dans VBA, je peux faire ce qui suit:

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

De sorte que si C > 0 Je reçois A=B+C et CA=B

Y a-t-il un opérateur ou une fonction qui me permettra de faire ces Conditions inline dans le code MATLAB?

25
demandé sur Lance Roberts 2013-01-30 23:36:36

7 réponses

Il n'y a pas d'opérateur ternaire dans Matlab. Vous pouvez, bien sûr, écrire une fonction qui le ferait. Par exemple, la fonction suivante fonctionne comme iif, avec n-d de l'état, et avec des chiffres et des cellules pour les résultats a et b:

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

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

out(cond) = a;

Pour une solution plus avancée, il existe un moyen de créer une fonction en ligne qui peut même faire elseif, comme indiqué dans Ce billet de blog sur les manigances de la fonction anonyme :

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

Vous utilisez cette fonction comme

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

Où vous remplacez les points par un nombre quelconque de paires condition/valeur supplémentaires.

La façon dont cela fonctionne est qu'il choisit parmi les valeurs de la première, dont la condition est vraie. 2*find(),1,'first') fournit l'index dans les arguments de valeur.

24
répondu Jonas 2013-01-30 20:41:30

Que diriez-vous simplement d'utiliser le fait que MATLAB convertit automatiquement les types de variables lorsque requis par l'opération? Par exemple, logique de doubler.

Si vos variables sont scalaires doubles, votre code, je crois, peut être remplacé par

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

Dans ce cas, l'opérateur (c > 0) Valeurs 1 (Type logique) chaque fois que c > 0 et valeurs à 0 sinon.

31
répondu Alex 2013-12-23 10:35:20

Il N'y a pas de solution intégrée pour cela, mais vous pouvez écrire un IIF vous-même.

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
6
répondu kol 2013-01-30 20:38:18

D'autres ont déjà dit qu'il n'y avait pas d'opérateur ternaire ?: dans Matlab. Comme solution, je suggère cette fonction, qui prend trois fonctions au lieu de valeurs. Par conséquent, la quantité de calculs inutiles est minimisée et vous pouvez vérifier les conditions avant de commencer les calculs, par exemple si une valeur est vraiment numérique, ou finie, ou non nulle:

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

Utilisez-le comme ceci:

f = @(y)(iif(@(x)(x > 3), @(x)(x.^2), @(x)(x/2), y))
f(linspace(0,6,10))
6
répondu quazgar 2013-05-23 13:59:35

Inspiré par la réponse de Jonas, la fonction ci-dessous fonctionne également pour l'entrée de type mixte et les caractères, pour lesquels sa fonction n'est pas 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 : éliminé les options conditionnelles supplémentaires dans la branche de cellule, qui étaient apparemment les restes d'une erreur précédente, c'est probablement plus rapide, et certainement plus propre.

3
répondu hugovdberg 2014-12-27 23:39:07

Il y a maintenant une fonction tern sur L'échange de fichiers MathWorks: http://www.mathworks.com/matlabcentral/fileexchange/39735-functional-programming-constructs/content/tern.m

Le code est reproduit ici:

function varargout = tern(condition, true_action, false_action)

% out = tern(condition, true_action, false_action)
% 
% Ternary operator. If the first input is true, it returns the second
% input. Otherwise, it returns the third input. This is useful for writing
% compact functions and especially anonymous functions. Note that, like
% many other languages, if the condition is true, not only is the false
% condition not returned, it isn't even executed. Likewise, if the
% condition is false, the true action is never executed. The second and
% third arguments can therefore be function handles or values.
%
% Example:
%
% >> tern(rand < 0.5, @() fprintf('hi\n'), pi)
% ans =
%     3.1416
% >> tern(rand < 0.5, @() fprintf('hi\n'), pi)
% hi
%
% It works with multiple outputs as well.
%
% >> [min_or_max, index] = tern(rand < 0.5, ...
%                               @() min([4 3 5]), ...
%                               @() max([4 3 5]))
% min_or_max =
%      5
% index =
%      3
%
% Tucker McClure
% Copyright 2013 The MathWorks, Inc.

    if condition() % Works for either a value or function handle.
        [varargout{1:nargout}] = true_action();
    else
        [varargout{1:nargout}] = false_action();
    end

end
1
répondu Alex 2015-09-16 23:43:51

C'est plus un addenum à la réponse D'Alex.

La méthode D'Alex ne fonctionne pas quand vous voulez revenir inf

Dans ces cas, vous finissez souvent par obtenir un chiffre 0*inf, que MATLAB évaluera à NaN. Problématique... Nous pouvons éviter cette multiplication en utilisant une recherche à la place.

Par exemple, une fonction de barrière utile dans l'optimisation convexe est quelque chose qui se comporte comme log partout positif, et -inf ailleurs. Voici comment vous pourriez créer un tel fonction utilisant une recherche:

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

Les conditions en ligne sont un hack, et vous perdez l'évaluation paresseuse. Vous devez être prudent. Cependant, avoir du code sémantique est vraiment agréable, et il est plus facile de partager votre code lorsque vous ne pouvez pas garantir que les environnements de tout le monde sont les mêmes.

1
répondu enthdegree 2016-05-16 09:17:44