web-dev-qa-db-fra.com

Existe-t-il un opérateur IF conditionnel Matlab pouvant être placé en ligne, comme le IIF de VBA?

En VBA, je peux effectuer les tâches suivantes:

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

de sorte que si C> 0 je reçois A=B+C et C <= 0 je reçois A=B

Existe-t-il un opérateur ou une fonction qui me permettra d'effectuer ces conditions conditionnelles inline dans le code MATLAB?

27
Lance Roberts

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 une entrée n-d pour la condition, et avec des nombres 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 d’autres tâches, comme indiqué dans ce billet de blog sur les manigances anonymes de fonctions :

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 sélectionne parmi les valeurs la première dont la condition est vraie. 2*find(),1,'first') fournit l'index dans les arguments de valeur.

26
Jonas

Pourquoi ne pas simplement utiliser le fait que MATLAB convertit automatiquement les types de variable lorsque l'opération le requiert? Par exemple, logique de doubler.

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

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

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

33
Alex

D'autres ont déjà dit qu'il n'y a 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 les calculs de départ, 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
quazgar

Il n’existe pas de solution intégrée à cela, mais vous pouvez écrire vous-même un IIF .

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
kol

Inspiré par la réponse de Jonas, la fonction ci-dessous fonctionne également pour les entrées 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 la cellule, qui étaient apparemment les restes d’une erreur précédente, c’est probablement plus rapide et nettement plus propre.

3
hugovdberg

Il existe 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
Alex

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

La méthode d'Alex ne fonctionne pas lorsque vous souhaitez retourner inf

Dans ces cas, vous obtenez souvent un chiffre 0*inf que MATLAB évalue à NaN. Problématique ... Nous pouvons éviter cette multiplication en utilisant plutôt une recherche.

Par exemple, une fonction barrière utile dans l'optimisation convexe est quelque chose qui se comporte comme log partout positif, et -inf ailleurs. Voici comment créer une telle fonction à l'aide d'une recherche:

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

Les conditionnels en ligne sont un hack et vous perdez une évaluation paresseuse. Tu dois ê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 tous les utilisateurs sont les mêmes.

1
enthdegree