Je suis un peu surpris que MATLAB n'ait pas de fonction Map, alors j'en ai piraté une moi-même car c'est quelque chose dont je ne peux pas me passer. Existe-t-il une meilleure version? Existe-t-il une bibliothèque de programmation fonctionnelle quelque peu standard pour MATLAB qui me manque?
function results = map(f,list)
% why doesn't MATLAB have a Map function?
results = zeros(1,length(list));
for k = 1:length(list)
results(1,k) = f(list(k));
end
end
l'utilisation serait par exemple.
map( @(x)x^2,1:10)
La réponse courte: la fonction intégrée arrayfun
fait exactement ce que fait votre fonction map
pour les tableaux numériques:
>> y = arrayfun(@(x) x^2, 1:10)
y =
1 4 9 16 25 36 49 64 81 100
Il existe deux autres fonctions intégrées qui se comportent de la même manière: cellfun
(qui fonctionne sur les éléments des tableaux de cellules) et structfun
(qui opère sur chaque champ d'une structure).
Cependant, ces fonctions ne sont souvent pas nécessaires si vous profitez de la vectorisation, en particulier en utilisant les éléments opérateurs arithmétiques . Pour l'exemple que vous avez donné, une solution vectorisée serait:
>> x = 1:10;
>> y = x.^2
y =
1 4 9 16 25 36 49 64 81 100
Certaines opérations fonctionneront automatiquement sur plusieurs éléments (comme l'ajout d'une valeur scalaire à un vecteur) tandis que d'autres opérateurs ont une syntaxe spéciale pour les opérations par élément (désignée par un .
devant l'opérateur). De nombreuses fonctions intégrées dans MATLAB sont conçues pour fonctionner sur des arguments vectoriels et matriciels à l'aide d'opérations élémentaires (souvent appliquées à une dimension donnée, telles que sum
et mean
par exemple), et ne nécessitent donc pas de fonctions de carte.
Pour résumer, voici différentes façons de mettre en carré chaque élément d'un tableau:
x = 1:10; % Sample array
f = @(x) x.^2; % Anonymous function that squares each element of its input
% Option #1:
y = x.^2; % Use the element-wise power operator
% Option #2:
y = f(x); % Pass a vector to f
% Option #3:
y = arrayfun(f, x); % Pass each element to f separately
Bien sûr, pour une opération aussi simple, l'option # 1 est le choix le plus judicieux (et efficace).
En plus des opérations vectorielles et élémentaires, il existe également cellfun
pour mapper les fonctions sur les tableaux de cellules. Par exemple:
cellfun(@upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans =
'A' 'B' 'C'
Si 'UniformOutput' est vrai (ou non fourni), il tentera de concaténer les résultats en fonction des dimensions du tableau de cellules, donc
cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
Une solution assez simple, utilisant la vectorisation de Matlab serait:
a = [ 10 20 30 40 50 ]; % the array with the original values
b = [ 10 8 6 4 2 ]; % the mapping array
c = zeros( 1, 10 ); % your target array
Maintenant, en tapant
c( b ) = a
résultats
c = 0 50 0 40 0 30 0 20 0 10
c (b) est une référence à un vecteur de taille 5 avec les éléments de c aux indices donnés par b. Maintenant, si vous attribuez des valeurs à ce vecteur de référence, les valeurs d'origine dans c sont écrasées, car c (b) contient des références aux valeurs dans c et aucune copie.
Il semble que le arrayfun intégré ne fonctionne pas si le résultat requis est un tableau de fonctions: par exemple: map (@ (x) [x x ^ 2 x ^ 3], 1: 10)
de légers mods ci-dessous améliorent ce travail:
function results = map(f,list)
% why doesn't MATLAB have a Map function?
for k = 1:length(list)
if (k==1)
r1=f(list(k));
results = zeros(length(r1),length(list));
results(:,k)=r1;
else
results(:,k) = f(list(k));
end;
end;
end
Si matlab n'a pas de fonction de carte intégrée, cela peut être dû à des considérations d'efficacité. Dans votre implémentation, vous utilisez une boucle pour parcourir les éléments de la liste, ce qui est généralement mal vu dans le monde matlab. La plupart des fonctions matlab intégrées sont "vectorisées", i. e. il est plus efficace d'appeler une fonction sur un tableau entier que de le parcourir vous-même et d'appeler la fonction pour chaque élément.
En d'autres termes, cette
a = 1:10;
a.^2
est beaucoup plus rapide que cela
a = 1:10;
map(@(x)x^2, a)
en supposant votre définition de la carte.
Vous n'avez pas besoin de map
car une fonction scalaire qui est appliquée à une liste de valeurs est appliquée à chacune des valeurs et fonctionne donc de manière similaire à map
. Essayez
l = 1:10
f = @(x) x + 1
f(l)
Dans votre cas particulier, vous pourriez même écrire
l.^2