Я немного удивлен тем, что у MATLAB нет функции Map, поэтому я сам взломал ее, так как я не могу без нее жить. Есть ли лучшая версия? Есть ли какая-то стандартная библиотека функционального программирования для MATLAB там, где я отсутствую?
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
будет, например,
map( @(x)x^2,1:10)
Короткий ответ: встроенная функция ARRAYFUN делает именно то, что делает ваша функция map для числовых массивы:
>> y = arrayfun(@(x) x^2,1:10)
y =
1 4 9 16 25 36 49 64 81 100
Существуют две другие встроенные функции, которые ведут себя аналогично: CELLFUN (который работает с элементами массивов ячеек) и STRUCTFUN (который работает с каждым полем структуры).
Однако эти функции часто не нужны, если вы используете преимущества векторизации, в частности, используя арифметические операторы . Для примера, который вы указали, векторизованное решение будет:
>> x = 1:10;
>> y = x.^2
y =
1 4 9 16 25 36 49 64 81 100
Некоторые операции будут автоматически работать через элементы (например, добавление скалярного значения к вектору), в то время как другие операторы имеют специальный синтаксис для элементарной операции (обозначается символом "." перед оператором). Многие функции в MATLAB предназначены для работы с векторными и матричными аргументами с использованием элементарных операций и, следовательно, не требуют функций карты.
Подводя итог, вот несколько разных способов квадратизировать каждый элемент в массиве:
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
Конечно, для такой простой операции вариант №1 является наиболее разумным выбором.
В дополнение к векторным и элементарным операциям также существует cellfun
для отображения функций над массивами ячеек. Например:
cellfun(@upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans =
'A' 'B' 'C'
Если "UniformOutput" истинно (или не предоставлено), он попытается объединить результаты в соответствии с размерами массива ячеек, поэтому
cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
Довольно простое решение с использованием векторизации Matlab:
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
Теперь, набрав
c( b ) = a
возвращает
c = 0 50 0 40 0 30 0 20 0 10
c (b) является ссылкой на вектор размера 5 с элементами c по индексам, заданным b. Теперь, если вы Ассинг значения этого опорного вектора, исходные значения в с переписываются, так как с (б) содержит ссылки на значения в с и никаких копий.
Похоже, что встроенный arrayfun не работает, если нужен необходимый массив: например: отображение (@(x) [x x ^ 2 x ^ 3], 1:10)
небольшие модификации ниже делают эту работу лучше:
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
..., 'UniformOutput', false);
чтобы создать вывод массива ячеек, содержащий ваши массивы, затем отформатируйте и объедините их так, как вы хотите, в массив без ячеек.
Если у Matlab нет встроенной функции карты, это может быть связано с соображениями эффективности. В вашей реализации вы используете цикл для итерации по элементам списка, который, как правило, неодобрен в мире matlab. Большинство встроенных функций matlab являются "векторизованными", т.е. е. более эффективно вызывать функцию по всему массиву, чем перебирать ее самостоятельно и вызывать функцию для каждого элемента.
Другими словами, этот
a = 1:10;
a.^2
намного быстрее, чем этот
a = 1:10;
map(@(x)x^2, a)
предполагая ваше определение карты.
Вам не нужно map
, так как скалярная функция, применяемая к списку значений, применяется к каждому из значений и, следовательно, работает аналогично map
. Просто попробуйте
l = 1:10
f = @(x) x + 1
f(l)
В вашем конкретном случае вы даже можете написать
l.^2
Векционализация решения, как описано в предыдущих ответах, является, вероятно, лучшим решением для скорости. Векторизация также очень матраби и чувствует себя хорошо.
С учетом сказанного Matlab теперь имеет класс контейнера Map.
См. http://www.mathworks.com/help/matlab/map-containers.html
cellfun
и др., А не хеш-таблицах или парах ключ-значение.