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


100

Я трохи здивований, що 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: Не використовуйте для циклів, вони на кілька порядків повільніше, ніж векторизований розчин.
CookieOfFortune

15
З введенням JIT за петлі не приймайте штраф, який вони колись зробили.
MatlabDoug

@CookieOfFortune Я думаю, що це вже не так ...
Андер Бігурі,

2
@AnderBiguri Я думаю, що вони додали деякі вдосконалення, але це все набагато повільніше.
CookieOfFortune

Функціональна бібліотека на файлової біржі map, foldl(також відомий як reduce), select(він же filter), і інші незамінні ласощі. Рекомендовано (якщо вам доведеться використовувати Matlab).
Ахмед Фасіх

Відповіді:


133

Коротка відповідь: вбудована функція 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 є найбільш розумним (і ефективним) вибором.


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

2

Досить простим рішенням з використанням векторизації Матлаба було б:

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

Здається, що вбудований масив не працює, якщо необхідний результат - це масив функцій: наприклад: map (@ (x) [xx ^ 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);щоб створити вихід масиву комірок, що містить ваші масиви, а потім відформатувати та об'єднати їх, як би ви хочете, у неклітинне масив.
gnovice

0

Якщо 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

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

Маючи на увазі, Matlab тепер має клас контейнерів Map.

Див. Http://www.mathworks.com/help/matlab/map-containers.html


Оп говорить про функцію вищого порядку, тобто, cellfunтощо, а не хеш-таблиць або пар ключів-значень.
Ахмед Фасіх
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.