আমি মাতলাবে ফাংশনগুলির পরামিতিগুলির জন্য কীভাবে ডিফল্ট মান সেট করব?


127

মতলবতে ডিফল্ট যুক্তি থাকা কি সম্ভব? উদাহরণস্বরূপ, এখানে:

function wave(a, b, n, k, T, f, flag, fTrue=inline('0'))

আমি আসল সমাধানটি ওয়েভ ফাংশনের একটি argumentচ্ছিক যুক্তি হতে চাই। যদি এটি সম্ভব হয় তবে কেউ কি এটি করার সঠিক উপায় প্রদর্শন করতে পারেন? বর্তমানে, আমি উপরে যা পোস্ট করেছি তা চেষ্টা করছি এবং আমি পেয়েছি:

??? Error: File: wave.m Line: 1 Column: 37
The expression to the left of the equals sign is not a valid target for an assignment.

উত্তর:


151

আপনি চেষ্টা করার মতো এটি করার সরাসরি কোনও উপায় নেই।

স্বাভাবিক পদ্ধতিটি হল "ভারারাগস" ব্যবহার করা এবং যুক্তি সংখ্যার বিপরীতে পরীক্ষা করা। কিছুটা এইরকম:

function f(arg1, arg2, arg3)

  if nargin < 3
    arg3 =   'some default'
  end

end

এখানে কয়েকটি কল্পিত জিনিস রয়েছে যা আপনি করতে পারেন isemptyইত্যাদি ইত্যাদি and এবং আপনি কিছু প্যাকেজগুলির জন্য মতলব কেন্দ্রীয়ের দিকে নজর রাখতে চাইতে পারেন যা এই ধরণের জিনিসগুলিকে বান্ডিল করে।

আপনি কটাক্ষপাত থাকতে পারে varargin, nargchkইত্যাদি তারা দরকারী জিনিস এই সাজানোর জন্য ফাংশন। ভারারাগস আপনাকে চূড়ান্ত আর্গুমেন্টগুলির একটি চলক সংখ্যা ছেড়ে দেওয়ার অনুমতি দেয়, তবে এটি কিছু / সমস্তর জন্য ডিফল্ট মানগুলির সমস্যাটি পেতে পারে না।


58

আমি inputParserডিফল্ট বিকল্পগুলি সেট করার সাথে মোকাবিলা করতে অবজেক্টটি ব্যবহার করেছি । মতলব আপনি প্রশ্নের মধ্যে উল্লেখ করা অজগর মত ফর্ম্যাটটি গ্রহণ করবেন না, তবে আপনি এই ফাংশনটি কল করতে সক্ষম হবেন:

wave(a,b,n,k,T,f,flag,'fTrue',inline('0'))

আপনি waveফাংশনটি এভাবে সংজ্ঞায়িত করার পরে :

function wave(a,b,n,k,T,f,flag,varargin)

i_p = inputParser;
i_p.FunctionName = 'WAVE';

i_p.addRequired('a',@isnumeric);
i_p.addRequired('b',@isnumeric);
i_p.addRequired('n',@isnumeric);
i_p.addRequired('k',@isnumeric);
i_p.addRequired('T',@isnumeric);
i_p.addRequired('f',@isnumeric);
i_p.addRequired('flag',@isnumeric); 
i_p.addOptional('ftrue',inline('0'),1);    

i_p.parse(a,b,n,k,T,f,flag,varargin{:});

এখন মান ফাংশনে অতিক্রান্ত হওয়া মাধ্যমে উপলব্ধ i_p.Results। এছাড়াও, আমি নিশ্চিত করতে পারি না যে কীভাবে যাচাই করতে হবে যে পরামিতিটির জন্য পাস হয়েছে ftrueএটি একটি inlineফাংশন ছিল তাই ভ্যালিডেটরকে ফাঁকা রেখে দিয়েছিল।


7
সেরা হিসাবে আমি বলতে পারি, এটি , পছন্দসই পদ্ধতি। এটি পরিষ্কার, স্ব-ডকুমেন্টিং (আরও অনেক কিছু if narginস্টেটম্যানদের), বজায় রাখা সহজ, কমপ্যাক্ট এবং নমনীয়।
JnBrymn

19

আরেকটি সামান্য কম হ্যাকি উপায়

function output = fun(input)
   if ~exist('input','var'), input='BlahBlahBlah'; end
   ...
end

আপনি সি কোড তৈরি করতে ম্যাটল্যাব কোডার ব্যবহার করতে গেলে এই বিকল্পটি কাজ করে না, কারণ কোডার "বিদ্যমান" ফাংশন সমর্থন করে না।
ডেভ টিলম্যান

10

হ্যাঁ, আপনি যেমন লিখেছেন তেমন দক্ষতা রাখলে এটি সত্যিই ভাল লাগবে। তবে এটি ম্যাটল্যাবে সম্ভব নয়। আমার অনেকগুলি ইউটিলিটিস যা আর্গুমেন্টগুলির জন্য ডিফল্টকে মঞ্জুরি দেয় তা প্রারম্ভিকভাবে সুস্পষ্ট চেক দিয়ে এইভাবে লেখা থাকে:

if (nargin<3) or isempty(myParameterName)
  MyParameterName = defaultValue;
elseif (.... tests for non-validity of the value actually provided ...)
  error('The sky is falling!')
end

ঠিক আছে, তাই আমি সাধারণত আরও ভাল, আরও বর্ণনামূলক ত্রুটি বার্তা প্রয়োগ করব। দেখুন যে একটি খালি ভেরিয়েবলের জন্য চেকটি ব্যবহারকারীকে একটি ভেরিয়েবলের স্থানধারক হিসাবে একটি খালি জোরে বন্ধনীর মধ্যে প্রবেশ করতে দেয়, [], যা তার ডিফল্ট মানটি গ্রহণ করবে। যদিও লেখকের অবশ্যই খালি যুক্তিটিকে তার ডিফল্ট মান দিয়ে প্রতিস্থাপন করতে কোড সরবরাহ করতে হবে।

অনেকগুলি প্যারামিটারগুলির সাথে আরও পরিশীলিত আমার ইউটিলিটিগুলি যার মধ্যে ডিফল্ট আর্গুমেন্ট রয়েছে সেগুলি প্রায়শই ডিফল্ট আর্গুমেন্টের জন্য সম্পত্তি / মান জোড় ইন্টারফেস ব্যবহার করবে। এই মৌলিক দৃষ্টান্তটি হ্যান্ডেল গ্রাফিক্স সরঞ্জামগুলিতে মাতলাব, পাশাপাশি অপটিসেট, ওডসেট ইত্যাদিতে দেখা যায়

এই সম্পত্তি / মান জোড়গুলির সাথে কাজ করার মাধ্যম হিসাবে আপনাকে কোনও ভার্শনে সম্পূর্ণরূপে চলক সংখ্যক যুক্তি যুক্ত করার উপায় হিসাবে, ভারারগিন সম্পর্কে শিখতে হবে। এই জাতীয় সম্পত্তি / মান জোড় , পার্স_পিভি_পিয়ারস.এম . নিয়ে কাজ করার জন্য আমি একটি ইউটিলিটি লিখেছি (এবং পোস্ট করেছি) । এটি আপনাকে সম্পত্তি / মান জোড়কে ম্যাটল্যাব স্ট্রাকচারে রূপান্তর করতে সহায়তা করে। এটি আপনাকে প্রতিটি প্যারামিটারের জন্য ডিফল্ট মান সরবরাহ করতে সক্ষম করে। প্যারামিটারগুলির অপ্রতিরোধ্য তালিকাটিকে কাঠামোতে রূপান্তর করা ম্যাটল্যাবগুলিতে এগুলি পাস করার খুব সুন্দর উপায়।


7

"চেষ্টা" ব্যবহার করে কোনও ফাংশনে ডিফল্ট মান সেট করার এটি আমার সহজ উপায়:

function z = myfun (a,varargin)

%% Default values
b = 1;
c = 1;
d = 1;
e = 1;

try 
    b = varargin{1};
    c = varargin{2};
    d = varargin{3};
    e = varargin{4};
end

%% Calculation
z = a * b * c * d * e ;
end

শুভেচ্ছা সহ!



3

একটি 'হ্যাক' রয়েছে যা ব্যবহার করা যেতে পারে যদিও এটি মাতলাব থেকে এক পর্যায়ে সরিয়ে দেওয়া হতে পারে: ফাংশন ইভাল আসলে দুটি যুক্তি গ্রহণ করে যার মধ্যে প্রথমটি ত্রুটি দেখা দিলে দ্বিতীয়টি চালানো হয়।

সুতরাং আমরা ব্যবহার করতে পারেন

function output = fun(input)
   eval('input;', 'input = 1;');
   ...
end

যুক্তিটির জন্য ডিফল্ট হিসাবে মান 1 ব্যবহার করতে


3

আমি বিশ্বাস করি যে আমি এই তিনটি লাইন কোড (লাইন মোড়ানো ব্যতীত) হাতে নিয়ে এই সমস্যাটি মোকাবিলার জন্য বেশ নিখুঁত উপায় পেয়েছি। আমি যে ফাংশনটি লিখছি তা থেকে নীচে সরাসরি তুলে নেওয়া হয়েছে এবং এটি মনে করা হিসাবে কাজ করবে বলে মনে হচ্ছে:

defaults = {50/6,3,true,false,[375,20,50,0]}; %set all defaults
defaults(1:nargin-numberForcedParameters) = varargin; %overload with function input
[sigma,shifts,applyDifference,loop,weights] = ...
     defaults{:}; %unfold the cell struct

ভেবেছিলাম আমি এটি ভাগ করে নেব।


3

আমি বিভ্রান্ত হয়েছি কেউ মতলবের অন্যতম বিকাশকারী লরেনের এই ব্লগ পোস্টটি দেখায়নি। পদ্ধতির উপর ভিত্তি করে এই vararginসমস্ত অন্তহীন এবং বেদনাদায়ক if-then-elseবা switchসংঘবদ্ধ শর্তযুক্ত কেসগুলি এড়িয়ে চলে । যখন কয়েকটি ডিফল্ট মান থাকে, তখন প্রভাবটি নাটকীয় । লিঙ্কযুক্ত ব্লগের একটি উদাহরণ এখানে:

function y = somefun2Alt(a,b,varargin)
% Some function that requires 2 inputs and has some optional inputs.

% only want 3 optional inputs at most
numvarargs = length(varargin);
if numvarargs > 3
    error('myfuns:somefun2Alt:TooManyInputs', ...
        'requires at most 3 optional inputs');
end

% set defaults for optional inputs
optargs = {eps 17 @magic};

% now put these defaults into the valuesToUse cell array, 
% and overwrite the ones specified in varargin.
optargs(1:numvarargs) = varargin;
% or ...
% [optargs{1:numvarargs}] = varargin{:};

% Place optional args in memorable variable names
[tol, mynum, func] = optargs{:};

আপনি যদি এখনও এটি না পান, তবে লরেনের সম্পূর্ণ ব্লগ পোস্টটি পড়ার চেষ্টা করুন। আমি একটি ফলোআপ ব্লগ পোস্ট লিখেছি যা হারিয়ে যাওয়া অবস্থানগত ডিফল্ট মানগুলির সাথে সম্পর্কিত deals আমি আপনাকে বোঝাতে চাইছি এরকম কিছু লিখতে পারেন:

somefun2Alt(a, b, '', 42)

এবং এখনও প্যারামিটারের epsজন্য ডিফল্ট মান রয়েছে tol(এবং অবশ্যই @magicকলব্যাক func)। লরেনের কোড এটিকে সামান্য তবে কৌতূহলী পরিবর্তনের মাধ্যমে মঞ্জুরি দেয়।

অবশেষে, এই পদ্ধতির মাত্র কয়েকটি সুবিধা:

  1. এমনকি অনেকগুলি ডিফল্ট থাকলেও বয়লারপ্লেট কোডটি বিশাল আকারে পায় না ( if-then-elseপদ্ধতির পরিবারের বিপরীতে , যা প্রতিটি নতুন ডিফল্ট মান দিয়ে দীর্ঘায়িত হয়)
  2. সমস্ত খেলাপি এক জায়গায়। এর মধ্যে যদি কোনওটির পরিবর্তনের প্রয়োজন হয় তবে আপনার দেখার জন্য কেবলমাত্র একটি জায়গা রয়েছে।

ট্রথকে বলা যেতে পারে, এর অসুবিধাও রয়েছে। আপনি যখন মাতলাব শেলের মধ্যে ফাংশনটি টাইপ করেন এবং এর পরামিতিগুলি ভুলে যান, আপনি vararginএকটি ইঙ্গিত হিসাবে একটি অপ্রয়োজনীয় দেখতে পাবেন । এটি মোকাবেলা করার জন্য, আপনাকে একটি অর্থবহ ব্যবহারের ধারাটি লেখার পরামর্শ দেওয়া হচ্ছে।


আপনার ফলোআপ ব্লগ পোস্টের লিঙ্কটি নষ্ট হয়েছে; আপনি এটা ঠিক করতে পারবো?
ইকুয়েঘে

2

সচেতন হওয়ার পর ASSIGNIN (ধন্যবাদ এই উত্তরটি দ্বারা B3 ) এবং EVALIN আমি দুটি ফাংশন পরিশেষে একটি খুব সহজ কলিং গঠন প্রাপ্ত লিখেছিলেন:

setParameterDefault('fTrue', inline('0'));

এখানে তালিকা রয়েছে:

function setParameterDefault(pname, defval)
% setParameterDefault(pname, defval)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% sets the parameter NAMED pname to the value defval if it is undefined or
% empty

if ~isParameterDefined('pname')
    error('paramDef:noPname', 'No parameter name defined!');
elseif ~isvarname(pname)
    error('paramDef:pnameNotChar', 'pname is not a valid varname!');
elseif ~isParameterDefined('defval')
    error('paramDef:noDefval', ['No default value for ' pname ' defined!']);
end;

% isParameterNotDefined copy&pasted since evalin can't handle caller's
% caller...
if ~evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')'])
    callername = evalin('caller', 'mfilename');
    warnMsg = ['Setting ' pname ' to default value'];
    if isscalar(defval) || ischar(defval) || isvector(defval)
        warnMsg = [warnMsg ' (' num2str(defval) ')'];
    end;
    warnMsg = [warnMsg '!'];
    warning([callername ':paramDef:assigning'], warnMsg);
    assignin('caller', pname, defval);
end

এবং

function b = isParameterDefined(pname)
% b = isParameterDefined(pname)
% Author: Tobias Kienzler (https://stackoverflow.com/users/321973)
% returns true if a parameter NAMED pname exists in the caller's workspace
% and if it is not empty

b = evalin('caller',  ['exist(''' pname ''', ''var'') && ~isempty(' pname ')']) ;

1

এটি মাতলাব ম্যানুয়াল থেকে কম-বেশি তোলা হয়েছে ; আমি কেবল উত্তীর্ণের অভিজ্ঞতা পেয়েছি ...

function my_output = wave ( a, b, n, k, T, f, flag, varargin )
  optargin = numel(varargin);
  fTrue = inline('0');
  if optargin > 0
    fTrue = varargin{1};
  end
  % code ...
end

1
কোডটি সংশোধন করে বেশ কয়েকটি ত্রুটি হয়েছিল। প্রথমত, "optargin" সংজ্ঞায়িত করা দরকার। দ্বিতীয়ত, "ভারারগিন" হ'ল একটি সেল অ্যারে যা পরবর্তী সমস্ত ইনপুট সংগ্রহ করে, সুতরাং আপনাকে সেগুলি থেকে মানগুলি সরাতে সেল অ্যারে সূচক ব্যবহার করতে হবে।
gnovice

আমার দৃষ্টি পরীক্ষা করা দরকার; আমি কসম
খেয়েছি

@ কাইল: চিন্তা করার দরকার নেই, আমরা সকলেই ভুল করে থাকি। এ কারণেই আমি এসও-র উইকি-ইশ শৈলী পছন্দ করি: আমি যদি কিছু নির্লিপ্ত টাইপ করি তবে সাধারণত আমার আশেপাশে অন্য কেউ আছেন যা এটিকে ধরতে পারে এবং তা দ্রুত সমাধান করতে পারে। =)
জ্নোভাইস

1

মতলব এটির জন্য কোনও প্রক্রিয়া সরবরাহ করে না, তবে আপনি ইউজারল্যান্ড কোডে এমন একটি নির্মাণ করতে পারেন যা ইনপুটপার্সারের চেয়ে শক্ত বা "যদি নার্গিন <1 ..." সিকোয়েন্স থাকে।

function varargout = getargs(args, defaults)
%GETARGS Parse function arguments, with defaults
%
% args is varargin from the caller. By convention, a [] means "use default".
% defaults (optional) is a cell vector of corresponding default values

if nargin < 2;  defaults = {}; end

varargout = cell(1, nargout);
for i = 1:nargout
    if numel(args) >= i && ~isequal(args{i}, [])
        varargout{i} = args{i};
    elseif numel(defaults) >= i
        varargout{i} = defaults{i};
    end
end

তারপরে আপনি এটিকে আপনার ফাংশনগুলিতে এভাবে কল করতে পারেন:

function y = foo(varargin)
%FOO 
%
% y = foo(a, b, c, d, e, f, g)

[a, b,  c,       d, e, f, g] = getargs(varargin,...
{1, 14, 'dfltc'});

ফর্ম্যাটিংটি একটি কনভেনশন যা আপনাকে প্যারামিটারের নামগুলি থেকে তাদের ডিফল্ট মানগুলিতে পড়তে দেয়। আপনি getচ্ছিক প্যারামিটার ধরণের স্পেসিফিকেশন (ত্রুটি সনাক্তকরণ বা অন্তর্ভুক্ত রূপান্তরকরণের জন্য) এবং আর্গুমেন্টের গণনা ব্যাপ্তির সাথে আপনার গেটার্গগুলি () প্রসারিত করতে পারেন।

এই পদ্ধতির দুটি ত্রুটি রয়েছে। প্রথমত, এটি ধীর গতির, সুতরাং আপনি এটিকে ফাংশনগুলির জন্য ব্যবহার করতে চান না যা লুপগুলিতে ডাকা হয়। দ্বিতীয়ত, মতলবের ফাংশন সহায়তা - কমান্ড লাইনে স্বতঃপূরণ ইঙ্গিত - ভারারগিন ফাংশনগুলির জন্য কাজ করবেন না। তবে এটি বেশ সুবিধাজনক।


0

আপনি parseparamsকমান্ডটি মাতলাব ব্যবহার করতে পারেন ; ব্যবহারের মত দেখতে হবে:

function output = wave(varargin);
% comments, etc
[reg, props] = parseparams(varargin);
ctrls = cell2struct(props(2:2:end),props(1:2:end),2);  %yes this is ugly!
a = reg{1};
b = reg{2};
%etc
fTrue = ctrl.fTrue;

0
function f(arg1, arg2, varargin)

arg3 = default3;
arg4 = default4;
% etc.

for ii = 1:length(varargin)/2
  if ~exist(varargin{2*ii-1})
    error(['unknown parameter: ' varargin{2*ii-1}]);
  end;
  eval([varargin{2*ii-1} '=' varargin{2*ii}]);
end;

যেমন f(2,4,'c',3)প্যারামিটার c3 হয়ে যায় be


0

আপনি যদি অষ্টা ব্যাবহার করেন তবে আপনি এটি এর মতো করতে পারেন - তবে দুঃখের বিষয় মতলব এই সম্ভাবনাটিকে সমর্থন করে না

function hello (who = "World")
  printf ("Hello, %s!\n", who);
endfunction

( ডক থেকে নেওয়া )


0

আমি এটি কিছুটা অবজেক্ট ওরিয়েন্টেড উপায়ে করতে পছন্দ করি। ওয়েভ কল করার আগে () আপনার কিছু যুক্তি একটি কাঠামোর মধ্যে সংরক্ষণ করুন, যেমন। এক পরামিতি বলা হয়:

parameters.flag =42;
parameters.fTrue =1;
wave(a,b,n,k,T,f,parameters);

তরঙ্গ ফাংশনের মধ্যে তারপরে পরীক্ষা করুন যে স্ট্রাক্ট প্যারামিটারগুলিতে 'পতাকা' নামক একটি ক্ষেত্র রয়েছে এবং যদি তাই হয় তবে এর মানটি খালি নয়। তারপরে এটির পূর্বে আপনি নির্ধারিত একটি ডিফল্ট মান বা প্যারামিটার স্ট্রাক্টে একটি আর্গুমেন্ট হিসাবে প্রদত্ত মানটিকে আটবার নির্ধারণ করুন:

function output = wave(a,b,n,k,T,f,parameters)
  flagDefault=18;
  fTrueDefault=0;
  if (isfield(parameters,'flag') == 0 || isempty(parameters.flag)),flag=flagDefault;else flag=parameters.flag; end
  if (isfield(parameter,'fTrue') == 0 || isempty(parameters.fTrue)),fTrue=fTrueDefault;else fTrue=parameters.fTrue; end
  ...
end

এটি বৃহত সংখ্যক যুক্তি পরিচালনা করতে সহজ করে তোলে কারণ এটি প্রদত্ত যুক্তিগুলির ক্রমের উপর নির্ভর করে না। এটি বলেছিল, এটি যদি পরে আপনাকে আরও যুক্তি যুক্ত করতে হয় তবে এটি সহায়ক because


নাম-মান জোড়ার MATLAB মানকে অনুসরণ করবেন না কেন? wave(a,b,'flag',42,'fTrue',1)
ক্রিস লুয়েঙ্গো

এটি অবশ্যই একটি বিকল্প, বিশেষত যখন কয়েকটিতে পরামিতি থাকে। বিপুল সংখ্যক নাম-মান জোড়ের সাথে তরঙ্গ () কল করা তবে কোডের পঠনযোগ্যতা হ্রাস করতে পারে। আমি প্রায়শই নির্দিষ্ট ইনপুটগুলিকে স্ট্রাক্টগুলিতে গ্রুপ করতে পছন্দ করি।
CheshireCat
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.