Функция карты в MATLAB? - PullRequest
94 голосов
/ 11 июня 2009

Я немного удивлен, что в 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)

Ответы [ 7 ]

130 голосов
/ 11 июня 2009

Краткий ответ: встроенная функция 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 предназначены для работы с векторными и матричными аргументами с использованием поэлементных операций (часто применяемых к данному измерению, таких как sum и mean например), и, следовательно, не требуют функций карты.

Подводя итог, можно привести несколько различных способов возведения в квадрат каждого элемента в массиве:

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 является наиболее разумным (и эффективным) выбором.

10 голосов
/ 12 июня 2009

В дополнение к векторным и поэлементным операциям, есть также cellfun для отображения функций по массивам ячеек. Например:

cellfun(@upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans = 
    'A'    'B'    'C'

Если 'UniformOutput' равен true (или не указан), он попытается объединить результаты в соответствии с размерами массива ячеек, поэтому

cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
2 голосов
/ 17 ноября 2011

Довольно простое решение, использующее векторизацию 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. Теперь, если вы присваиваете значения этому эталонному вектору, исходные значения в c перезаписываются, поскольку c (b) содержит ссылки на значения в c и не содержит копий.

1 голос
/ 26 апреля 2012

Кажется, что встроенный 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
0 голосов
/ 03 мая 2014

Векторизация решения, как описано в предыдущих ответах, является, вероятно, лучшим решением для скорости. Векторизация также очень Matlaby и чувствует себя хорошо.

С учетом сказанного, у Matlab теперь есть класс контейнера Map.

См. http://www.mathworks.com/help/matlab/map-containers.html

0 голосов
/ 11 июня 2009

Вам не нужно map, поскольку скалярная функция, которая применяется к списку значений, применяется к каждому из значений и, следовательно, работает аналогично map. Просто попробуйте

l = 1:10
f = @(x) x + 1

f(l)

В вашем конкретном случае вы могли бы даже написать

l.^2
0 голосов
/ 11 июня 2009

Если в Matlab нет встроенной функции map, это может быть связано с соображениями эффективности. В вашей реализации вы используете цикл для перебора элементов списка, который обычно не одобряется в мире Matlab. Большинство встроенных функций matlab являются «векторизованными», т.е. е. более эффективно вызывать функцию для всего массива, чем выполнять ее итерацию самостоятельно и вызывать функцию для каждого элемента.

Другими словами, это


a = 1:10;
a.^2

намного быстрее, чем этот


a = 1:10;
map(@(x)x^2, a)

при условии вашего определения карты.

...