Функция карты в MATLAB?

84

Я немного удивлен тем, что у 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)
  • 12
    Урок № 1, переходящий от других языков к Matlab: не используйте для циклов, они на несколько порядков медленнее, чем векторизованное решение.
  • 1
    Как насчет рекурсии?
Показать ещё 4 комментария
Теги:
functional-programming
map-function

7 ответов

127

Короткий ответ: встроенная функция 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 является наиболее разумным выбором.

  • 2
    Следует отметить, что вариант 1 не только проще, но и быстрее (по сравнению с вариантом 3, 2 должен быть очень похож на 1)!
10

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

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

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

cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
3

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

1

Похоже, что встроенный 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
  • 5
    ARRAYFUN будет работать для вашего примера, вам просто нужно будет включить входные аргументы ..., 'UniformOutput', false); чтобы создать вывод массива ячеек, содержащий ваши массивы, затем отформатируйте и объедините их так, как вы хотите, в массив без ячеек.
1

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

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


a = 1:10;
a.^2

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


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

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

  • 2
    Я думаю, что его точка зрения была не в том, что он хотел, чтобы он обязательно зацикливался, а просто в том, чтобы иметь в результате массив результатов применения предоставленной функции к соответствующим элементам предоставленного массива. Я не знаю много matlab, но кажется, что arrayfun делает свою работу.
  • 1
    Большинство встроенных функций и операторов Matlab уже делают это: они работают с каждым элементом входного массива и возвращают соответствующий массив результатов.
0

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

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

f(l)

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

l.^2
  • 9
    -1: Это на самом деле не так. Matlab не обладает достаточно сильной системой типов для определения скалярных функций. f вызывается с вектором, и в вашем примере выполняется сложение одного вектора. Чтобы убедиться в этом, профилируйте пример кода («профиль включен» перед запуском кода, затем «профиль отключен» после него). Вы увидите, что есть один звонок для f.
-1

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

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

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

  • 0
    Оператор говорит о функции высшего порядка, то есть cellfun и др., А не хеш-таблицах или парах ключ-значение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню