Sometimes it is desired to make several calls in one command. A simple example could be strrep. Assume you want to replace all parentheses with brackets, all commas with dots and then remove all double quotations. The following pseudo code could then be desired:
strrep(myString, '()', '[]', ',', '.', '"', '')
Is there any way to accomplish this? You could of course go with:
strrep(strrep(strrep(myString, '()', '[]'), ',', '.'), '"', '')
Or save the strings in a cell array and use this in a for loop, but both solutions are incredibly ugly.
The most desired answer, is one that is generic for all functions that work in a similar way.
To directly answer your question, there is really no consistent way of doing this, no. It really depends on the function. If you search the documentation you will often find a way to do this. With strings, at least, you can usually pass cell arrays in place of strings to perform operations on multiple strings, and in this case multiple operations on the same string.
A Solution for This Particular Example
You can easily use regexprep to do this for you. You can pass a cell array of the expressions to match with a corresponding cell array of the replacement values.
regexprep('abc', {'a', 'b', 'c'}, {'1', '2', '3'});
%// '123'
For your specific example, you would do something like:
regexprep(myString, {'\(\)', ',', '"'}, {'[]', '.', ''})
And as an example:
myString = 'This, is a () "string"';
regexprep(myString, {'\(\)', ',', '"'}, {'[]', '.', ''})
%// 'This. is a [] string'
If you don't want to worry about escaping all of the expressions to be regex-compatible, you can use regexptranslate to do that for you.
expressions = regexptranslate('escape', {'()', ',', '"'});
regexprep(myString, expressions, {'[]', '.', ''});
Say you want function foo to work like this:
foo(Variable,Parameter1,Value1);
foo(Variable,Parameter1_1,Value1,Parameter2,Value2,...);
then using recursion:
function[Variable]=FooBar(Variable,varargin)
N=nargin-1; %\\ Count the input parameters
if N>=2
Parameter=varargin{1};
Value=varargin{2};
% Process the first Parameter-value pair
Variable=FooBar(Variable,varargin{3:N}); %\\ Cut first Parameter-Value pair off and pass the rest to foo again
end
This approach allows you to use chain of single parameters, pairs, triplets, quadruplets, etc.
In this perticullar example the pairs are executed as LIFO stack and last unpaired Parameter is ignored. You can also add some conditions to implement foo(IN,Parameter1,Value1,Modifier,Parameter2,Value2,...) and many other properties...
For your perticullar example:
function[MyString]=FooBar(MyString,varargin)
N=nargin-1; %\\ Count the input parameters
if N>=2
Parameter=varargin{1};
Value=varargin{2};
MyString=regexprep(MyString,Parameter,Value)
MyString=FooBar(MyString,varargin{3:N});%\\ Cut first Parameter-Value pair off and pass the rest to foo again
end
Examples:
>> myString='This, is a () "string"';
FooBar(myString,'()','[]','"','',',','.')
ans = This. is a [] string
>> myString='This, is a ("string")';
FooBar(myString,'()','[]','"','',',','.')
ans = This. is a (string)
>> myString='This, is a ("string")';
FooBar(myString,'(','[',')',']','"','',',','.')
ans = This. is a [string]
As already said by #Suever your example can be solved by regexprep and #thewaywewalk has hinted that there is no "general" soluction for all function calls.
Note I do not advocate this as a good way to code -> but its a quirky question and thus here is a suitable quirky solution....
There is lots of reason why you shouldn't do this - namely a nightmare to debug but you could in theory do this with an "intelligent" self calling function...
% Create your own function which takes the following inputs:
% fHandle - function handle to the function of choice
% property - your starting variable
% varargin - a cell array (or single var) of variables to
% pass into the fHandle on each call
% see examples below...
function output = multipleCalls ( fHandle, property, varargin )
% call your primary function using feval and your inputs
% with the 1st group of inputs from the 1st varargin
if iscell ( varargin{1} )
output = feval ( fHandle, property, varargin{1}{:} );
else
output = feval ( fHandle, property, varargin{1} );
end
% remove the varargin variable which has just been used.
varargin(1) = [];
% are they aremore multiple call?
if ~isempty ( varargin )
% if so self call to apply the subsequent calls.
output = multipleCalls ( fHandle, output, varargin{:} );
end
end
% modifying your example to use this method:
multipleCalls( #strrep, 'This, is a () "string"', { '()', '[]' }, { ',', '.' }, { '"', '' } )
% Its probably a longer command and is it any clearer -> probably not...
% Here is another example:
% Create a silly anonymous function
sillyFunction = #(a,b) a + b
% Then you can use it in the same way:
% Where 0 is what you start with and then
% each time you want to add 1, then 2, then 3 and finally 4
multipleCalls ( sillyFunction, 0, 1, 2, 3, 4 )
Related
I would like to use inputParser on the function f(a,b,c,d), where a is mandatory and b-d are optional. I would like to keep b-d named = not use f(a, varargin), because that varargin doesn't tell you anything when you actually want to use the function. The simple p.parse(a,b,c,d) obviously does not work unless all 4 parameters are given.
The only way I know how to do it is to use setDefaultValue(argname, value), and then use p.parse(...) for checks if needed. But is there a simple way to hack this using just inputParser (without tons of ifs)?
As a side question, there is no easy way to do named arguments like in C# in MATLAB, right? So I would have that f(a,b,c,d) and use as such. First argument is a, then b, then c ... But when the user wanted to call it like f(a, 'd', 3, 'c', 2), he could. In this example, he would keep default b and use 3 for d and 2 for c. Without tons of work on my side of course - I know how to do it, writing my own parsing of the thing, but I would like a simpler solution (like other person's parsing :))
Im going to give you an alternative answer: Don't be lazy, write docs.
If you do this:
function [out]= foo(a,b,c,d)
%FOO does foo things
%
% FOO(a,b) does very foo thins to a and b
%
% FOO(a,b,c) is quite foo-y on c also
%
% FOO(a,b,c,d) c and d are optional FOO things
if (nargin==3)
...
then if the user presses F1 or types help foo they will get all the information in the comments.
To have users able to put inputs such as foo(1,2,'d',5) in my code, I use the following "inputparser" for optional parameters:
function [c,d]=parse_inputs(argin)
opts= {'c','d'};
defaults=ones(length(opts),1);
% Check inputs
nVarargs = length(argin);
if mod(nVarargs,2)
error('InvalidInput','Invalid number of inputs')
end
% check if option has been passed as input
for ii=1:2:nVarargs
ind=find(ismember(opts,lower(argin{ii})));
if ~isempty(ind)
defaults(ind)=0;
else
error('InvalidInput',['Optional parameter "' argin{ii} '" does not exist' ]);
end
end
for ii=1:length(opts)
opt=opts{ii};
default=defaults(ii);
% if one option is not default, then extrac value from input
if default==0
ind=double.empty(0,1);jj=1;
while isempty(ind)
ind=find(isequal(opt,lower(argin{jj})));
jj=jj+1;
end
if isempty(ind)
error('InvalidInput',['Optional parameter "' argin{jj} '" does not exist' ]);
end
val=argin{jj};
end
switch opt
case 'c':
if default;
c=4;
else
c=val;
end
...
otherwise
error('InvalidInput',['Invalid input name:', num2str(opt),'\n No such option in SART()']);
end
end
Then The first thing I do inside foo is:
[c,d]=parse_inputs(varargin);
The first part of the question on how to handle varying number of inputs without varargin was answered well by Ander Biguri's answer.
Regarding the second part of the question on how to parse inputs in pairs, here is my simplified "input parser":
function parseVarargin( argin )
% Simplified function to parse varargin property-value pairs
% Read input arguments
if mod(numel(argin),2)
error('Uneven number of inputs')
end
for i = 1 : 2 : numel(argin)-1
if ~ischar(argin{i})
error('Properties must be strings')
end
isValid = evalin('caller', sprintf('exist(''%s'',''var'')', argin{i}));
if isValid && ~strcmp(argin{i},'MRX')
assignin('caller', argin{i}, argin{i+1})
else
error(['Undefined property %s. ', ...
'Please note case-sensitivity.'], argin{i});
end
end
To use it, simply set the default variable values and the call parseVarargin on varargin:
function foo( a, varargin )
%FOO general description
%
% Usage:
% foo(a)
% foo(a, 'property-value-pairs')
%
% Properties:
% b : This ...
% c : That ...
% Default property values
b = 1;
c = [];
% Read property-value paris
parseVarargin( varargin );
% Do other stuff
I am trying to define the following function in MATLAB:
file = #(var1,var2,var3,var4) ['var1=' num2str(var1) 'var2=' num2str(var2) 'var3=' num2str(var3) 'var4=' num2str(var4)'];
However, I want the function to expand as I add more parameters; if I wanted to add the variable vark, I want the function to be:
file = #(var1,var2,var3,var4,vark) ['var1=' num2str(var1) 'var2=' num2str(var2) 'var3=' num2str(var3) 'var4=' num2str(var4) 'vark=' num2str(vark)'];
Is there a systematic way to do this?
Use fprintf with varargin for this:
f = #(varargin) fprintf('var%i= %i\n', [(1:numel(varargin));[varargin{:}]])
f(5,6,7,88)
var1= 5
var2= 6
var3= 7
var4= 88
The format I've used is: 'var%i= %i\n'. This means it will first write var then %i says it should input an integer. Thereafter it should write = followed by a new number: %i and a newline \n.
It will choose the integer in odd positions for var%i and integers in the even positions for the actual number. Since the linear index in MATLAB goes column for column we place the vector [1 2 3 4 5 ...] on top, and the content of the variable in the second row.
By the way: If you actually want it on the format you specified in the question, skip the \n:
f = #(varargin) fprintf('var%i= %i', [(1:numel(varargin));[varargin{:}]])
f(6,12,3,15,5553)
var1= 6var2= 12var3= 3var4= 15var5= 5553
Also, you can change the second %i to floats (%f), doubles (%d) etc.
If you want to use actual variable names var1, var2, var3, ... in your input then I can only say one thing: Don't! It's a horrible idea. Use cells, structs, or anything else than numbered variable names.
Just to be crytsal clear: Don't use the output from this in MATLAB in combination with eval! eval is evil. The Mathworks actually warns you about this in the official documentation!
How about calling the function as many times as the number of parameters? I wrote this considering the specific form of the character string returned by your function where k is assumed to be the index of the 'kth' variable to be entered. Array var can be the list of your numeric parameters.
file=#(var,i)[strcat('var',num2str(i),'=') num2str(var) ];
var=[2,3,4,5];
str='';
for i=1:length(var);
str=strcat(str,file(var(i),i));
end
If you want a function to accept a flexible number of input arguments, you need varargin.
In case you want the final string to be composed of the names of your variables as in your workspace, I found no way, since you need varargin and then it looks impossible. But if you are fine with having var1, var2 in your string, you can define this function and then use it:
function str = strgen(varargin)
str = '';
for ii = 1:numel(varargin);
str = sprintf('%s var%d = %s', str, ii, num2str(varargin{ii}));
end
str = str(2:end); % to remove the initial blank space
It is also compatible with strings. Testing it:
% A = pi;
% B = 'Hello!';
strgen(A, B)
ans =
var1 = 3.1416 var2 = Hello!
I have a matlab struct which several levels (e.g. a.b(j).c(i).d). I would like to write a function which gives me the fields I want. If the struct has only one level, it would be easy:
function x = test(struct, label1)
x = struct.(label1)
end
E.g. if I have the struct a.b I could get b via: test('b'). However, this does not work with subfields, if I have a struct a.b.c I can't use test('b.c') to access it.
Is there any way to pass a string with the full field name (with dots) to a function to retrieve this field? Or is there even a better way to get only the fields that I select through the function arguments?
The goal? Sure, it would be a useless function for one fieldname, but I wan't to pass a list of fieldnames as argument to receive exactly these fields.
You should use subsref function:
function x = test(strct, label1)
F=regexp(label1, '\.', 'split');
F(2:2:2*end)=F;
F(1:2:end)={'.'};
x=subsref(strct, substruct(F{:}));
end
To access a.b.c you can use:
subsref(a, substruct('.', 'b', '.', 'c'));
The test function first splits the input using .as a delimiter and creates a cell array F where every other element is filled with . and then its elements are passed to substruct as arguments.
Note that if there are arrays of structs involved it will get the first one. For a.b(i).c(j).d passing b.c.d will return a.b(1).c(1).d. See this question for the way it should be handled.
As a side note, I renamed your input variable struct to strct because struct is a built-in MATLAB command.
One way is to create a self calling function to do this:
a.b.c.d.e.f.g = 'abc'
value = getSubField ( a, 'b.c.d.e.f.g' )
'abc'
function output = getSubField ( myStruct, fpath )
% convert the provided path to a cell
if ~iscell(fpath); fpath = strread ( fpath, '%s', 'delimiter', '.' ); end
% extract the field (should really check if it exists)
output = myStruct.(fpath{1});
% remove the one we just found
fpath(1) = [];
% if fpath still has items in it -> self call to get the value
if isstruct ( output ) && ~isempty(fpath)
% Pass in the sub field and the remaining fpath
output = getSubField ( output, fpath );
end
end
Function:
My MATLAB function has one output and several input arguments, most of which are optional, i.e.:
output=MyFunction(arg1,arg2,opt1,opt2,...,optN)
What I want to do:
I'd like to give only arg1, arg2 and the last optional input argument optN to the function. I used the tilde operator as follows:
output=MyFunction(str1,str2,~,~,...,true)
Undesired result:
That gives the following error message:
Error: Expression or statement is incorrect--possibly unbalanced (, {, or [.
The error points to the comma after the first tilde, but I don't know what to make of it to be honest.
Problem identification:
I use MATLAB 2013b, which supports the tilde operator.
According to MATLAB's documentation the above function call should work:
You can ignore any number of function inputs, in any position in the argument list. Separate consecutive tildes with a comma...
I guess there are a few workarounds, such as using '' or [] as inputs, but I'd really like to understand how to correctly use '~' because actually leaving inputs out allows me to use exist() when checking the input arguments of a function.
If you need any further info from me, please let me know.
Thank you very much!
The tilde is only for function declaration. Matlab's mlint recommends to replace unused arguments by ~. The result is a function declared like this function output = MyFunction(a, b, ~, c). This is a very bad practice.
Since you have a function where the parameters are optional, you must call the function with empty arguments output=MyFunction(str1,str2,[],[],...,true).
A better way to do it is to declare the function with the varargin argument and prepare your function for the different inputs:
function output = MyFunction(varargin)
if nargin == 1
% Do something for 1 input
elseif nargin == 2
% Do something for 3 inputs
elseif nargin == 3
% Do something for 3 inputs
else
error('incorrect number of input arguments')
end
It is even possible to declare your function as follows:
function output = MyFunction(arg1, arg2, varargin)
The declaration above will tell Matlab that you are expecting at least two parameters.
See the documentation of nargin here.
... and the documentation of varargin here
To have variable number of inputs, use varargin. Use it together with nargin.
Example:
function varlist2(X,Y,varargin)
fprintf('Total number of inputs = %d\n',nargin);
nVarargs = length(varargin);
fprintf('Inputs in varargin(%d):\n',nVarargs)
for k = 1:nVarargs
fprintf(' %d\n', varargin{k})
end
Let's say I have func1, func2 and func3. Is there any way to call them with a known argument having defined their names? (Or their pointers? handlers?)
Something like:
toBeRunned = [ 'func1'; 'func2'; 'func3' ];
// .. foreach entry of toBeRunned call the function with VAR params ..
This is what function handles are meant for.
toBeRun = {#func1, #func2, #func3};
for ix = 1:length(toBeRun)
fnArguments = {1, 2, 3, 'four'};
fnTmp = toBeRun{ix};
fnTmp(fnArguments{:});
end
A little more explanation on what we're doing here:
toBeRun is a cell array of function handles, just an arbitrary list. For a function written as an M-file, added the # is all the is required to create a function handle.
In order to evaluate the function, it needs to be removed from the cell array (into fnTmp in this case.) This is a syntax limitation of Matlab. You can also use fneval, but I usually do it this way.
Any arguments can be added as needed, in the usual way (e.g. fnTmp(1,2,3,'four')). But if you need this much abstraction, you may also need to use an arbitrary number of input arguments. The fnArguments cell is a pretty flexible way of accomplishing this.
Function feval:
for i = 1 : size(toBeRunned, 1)
feval(toBeRunned(i, :), argument);
end
Another way to accomplish it...
toBeRunned = { 'func1', 'func2', 'func3' };
% arguments to be provided to functions
VAR = { arg1, arg2, arg3, arg4 };
% preallocate space for results
results = cell(1, 3);
for i = 1 : length(toBeRunned)
% KEY part ...
toRun = eval( [ '#' boBeRunned{i} ] );
results{i} = toRun( VAR{:} );
end
Explanation of the key part of the code:
[] concatenates strings,
eval evaluates string as Matlab code. In the first iteration of the loop, line with eval equals to:
toRun = #func1;