Правильное использование eval или избегайте его в MATLAB - PullRequest
0 голосов
/ 10 мая 2018

В моем коде я использую определенный способ определения тестовых функций: в ячейке хранится логический тип тестов ('<=', '> =', '==' ...). После этого я хочу применить тест на конкретные значения. Причина, по которой я сохраняю тип теста, зависит от моего кода и позволяет мне писать код, не имея предварительных знаний о типе теста. Другим способом может быть указание test для каждого логического теста с использованием, например, switch, но в тот момент, когда я хочу этого избежать.

MWE

a{1}=[1 2 3 4];
a{2}=[5 1 4 6];

typeTest{1}='<=';
typeTest{2}='<';

%create function
funCheck=@(x,y)eval([num2str(x),y,'0']);

%works
funCheck(1,'<')

%apply on cell (does not work due to the array in a)
cellfun(funCheck,a,typeTest)

С этим синтаксисом невозможно одновременно использовать eval и векторное выражение ...

1 Ответ

0 голосов
/ 10 мая 2018

Отказ от использования eval в настоящее время довольно прост в MATLAB. Если вы определяете typeTest как набор функциональных дескрипторов вместо строк, вы на 99% пути:

a{1}=[1 2 3 4];
a{2}=[5 1 4 6];

typeTest{1}=@le; % <=
typeTest{2}=@lt; % <

%create function
funCheck=@(x,y)y(x,0);

%works
funCheck(1,typeTest{1})

%apply on cell
cellfun(funCheck,a,typeTest,'UniformOutput',false)

Обратите внимание, что я добавил 'UniformOutput',false к аргументам cellfun. Это создает массив ячеек в качестве выходных данных, где каждая ячейка является результатом отдыха для одного из элементов в a и соответствующего элемента в typeTest. То есть {1} проверяется с помощью TypeTest{1}, а a{2} проверяется с помощью TypeTest{2}.

Я бы на самом деле создал массив со всеми фактическими тестами, вот так:

checks = { @(x)x<=3 , @(x)x>4 };

Теперь вы кодируете оператор, а также правый операнд. Это дает вам возможность создавать другие типы чеков: @(x)var(x)<1e-3, @(x)max(diff(x))<1 и т. Д.

Чтобы применить каждую из этих проверок к каждому массиву данных, вы должны использовать bsxfun. Я попробовал следующее утверждение, но в Octave 3.0.0 оно работало некорректно (думаю, это может быть ошибкой):

bsxfun( @(fun,data){fun{1}(data{1})}, checks(:)', a(:) )

Создает массив ячеек 2x2 (число проверок, умноженное на количество массивов данных) с результатами.

Уродливая альтернатива вышесказанному, которая сработала:

cellfun( @(fun,data)fun(data), ...
         repmat(checks(:)',numel(a),1), ...
         repmat(a(:),1,numel(checks)), ...
         'UniformOutput',false)
...