web-dev-qa-db-fra.com

Comment puis-je indexer un tableau MATLAB renvoyé par une fonction sans l'affecter d'abord à une variable locale?

Par exemple, si je veux lire la valeur médiane de magic(5), je peux le faire comme ceci:

M = magic(5);
value = M(3,3);

pour obtenir value == 13. J'aimerais pouvoir faire quelque chose comme l'un de ceux-ci:

value = magic(5)(3,3);
value = (magic(5))(3,3);

se passer de la variable intermédiaire. Cependant, MATLAB se plaint de Unbalanced or unexpected parenthesis or bracket dans la première parenthèse avant le 3.

Est-il possible de lire les valeurs d'un tableau/matrice sans d'abord l'assigner à une variable?

345
Joe Kearney

En fait il est possible de faire ce que vous voulez, mais vous devez utiliser la forme fonctionnelle de l'opérateur d'indexation. Lorsque vous effectuez une opération d'indexation à l'aide de (), vous appelez en fait la fonction subsref . Donc, même si vous ne pouvez pas faire ceci:

value = magic(5)(3, 3);

Vous pouvez faire ceci:

value = subsref(magic(5), struct('type', '()', 'subs', {{3, 3}}));

Moche, mais possible. ;)

En général, il vous suffit de changer l'étape d'indexation en appel de fonction pour éviter que deux jeux de parenthèses ne se suivent immédiatement. Une autre façon de faire serait de définir votre propre fonction anonyme pour faire l'indexation en indice. Par exemple:

subindex = @(A, r, c) A(r, c);     % An anonymous function for 2-D indexing
value = subindex(magic(5), 3, 3);  % Use the function to index the matrix

Cependant, quand tout est dit et fait, la solution de variable locale temporaire est beaucoup plus lisible, et certainement ce que je suggérerais.

372
gnovice

Il y avait juste bon article de blog sur Loren sur l'art de Matlab il y a quelques jours avec quelques gemmes qui pourraient aider. En particulier, en utilisant des fonctions d'assistance telles que:

paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};

paren() peut être utilisé comme

paren(magic(5), 3, 3);

retournerais

ans = 16

Je suppose également que cela sera plus rapide que la réponse de gnovice, mais je n'ai pas vérifié (utilisez le profileur !!!). Cela étant dit, vous devez également inclure ces définitions de fonction quelque part. Personnellement, j’en ai fait des fonctions indépendantes sur mon parcours, car elles sont super utiles.

Ces fonctions et d’autres sont maintenant disponibles dans l’add-on , construction fonctionnelle disponible dans l’Explorateur de compléments MATLAB ou dans la console Échange de fichiers .

128
T. Furfaro

Que pensez-vous de l'utilisation de fonctionnalités non documentées:

>> builtin('_paren', magic(5), 3, 3)               %# M(3,3)
ans =
    13

ou pour les matrices de cellules:

>> builtin('_brace', num2cell(magic(5)), 3, 3)     %# C{3,3}
ans =
    13

Comme par magie :)


MISE À JOUR:

Mauvaise nouvelle, le hack ci-dessus ne fonctionne plus dans R2015b! C'est bien, il s'agissait de fonctionnalités non documentées et nous ne pouvons pas nous en prévaloir en tant que fonctionnalité prise en charge :)

Pour ceux qui se demandent où trouver ce genre de chose, regardez dans le dossier fullfile(matlabroot,'bin','registry'). Il y a un tas de fichiers XML qui répertorie toutes sortes de goodies. Soyez averti que l'appel direct de certaines de ces fonctions peut facilement bloquer votre session MATLAB.

75
Amro

Au moins dans MATLAB 2013a, vous pouvez utiliser getfield comme:

a=Rand(5);
getfield(a,{1,2}) % etc

pour obtenir l'élément en (1,2)

53
Ian M. García

malheureusement, la syntaxe comme magic(5)(3,3) n'est pas supportée par matlab. vous devez utiliser des variables intermédiaires temporaires. vous pouvez libérer la mémoire après utilisation, par exemple.

tmp = magic(3);
myVar = tmp(3,3);
clear tmp
15
second

Notez que si vous comparez les temps d'exécution à la méthode standard (attribuez le résultat puis accédez aux entrées), ils sont exactement les mêmes.

subs=@(M,i,j) M(i,j);
>> for nit=1:10;tic;subs(magic(100),1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0103

>> for nit=1:10,tic;M=magic(100); M(1:10,1:10);tlap(nit)=toc;end;mean(tlap)

ans =

0.0101

À mon avis, l'essentiel est: MATLAB n'a pas de pointeur, vous devez vivre avec.

12
titus

Cela pourrait être plus simple si vous créez une nouvelle fonction:

function [ element ] = getElem( matrix, index1, index2 )
    element = matrix(index1, index2);
end

et ensuite l'utiliser:

value = getElem(magic(5), 3, 3);
6
Vugar

Votre notation initiale est la manière la plus concise de procéder:

M = magic(5);  %create
value = M(3,3);  % extract useful data
clear M;  %free memory

Si vous faites cela en boucle, vous pouvez simplement réaffecter M à chaque fois et ignorer également l’instruction clear.

4
Andreas GS

Pour compléter la réponse d'Amro, vous pouvez utiliser feval au lieu de builtin. En réalité, il n'y a pas de différence, sauf si vous essayez de surcharger la fonction opérateur:

BUILTIN (...) est identique à FEVAL (...) sauf qu'il appellera la version intégrée d'origine de la fonction même s'il en existe une surchargée (pour que cela fonctionne, vous ne devez jamais surcharger BUILTIN).

>> feval('_paren', magic(5), 3, 3)               % M(3,3)
ans =
    13

>> feval('_brace', num2cell(magic(5)), 3, 3)     % C{3,3}
ans =
    13

Ce qui est intéressant, c’est que feval semble être un peu plus rapide que builtin (environ 3,5%), du moins dans Matlab 2013b, ce qui est étrange étant donné que feval doit vérifier si la fonction est surchargée, contrairement à builtin:

>> tic; for i=1:1e6, feval('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 49.904117 seconds.
>> tic; for i=1:1e6, builtin('_paren', magic(5), 3, 3); end; toc;
Elapsed time is 51.485339 seconds.
1
nirvana-msu