编写一个通过结构并创建结构数组的函数(处理批处理参数)

时间:2017-06-30 18:50:03

标签: python matlab for-loop recursion while-loop

能够获得一个函数句柄并在批处理模式下使用它(即运行输入参数的不同组合)我想编写一个获取结构的函数(未知的字段名称),然后创建一个结构数组如下例所示:

实施例

P是输入,BP是我们期望的输出

function BP = createBP(P)
%   P.A = 1:4;
%   P.B = {'a','b','c'};
% So the output BP will be 4*3 = 12 different combination arranged this way:
%           BP(1).A = 1
%           BP(1).B = 'a'
%           BP(2).A = 1
%           BP(2).B = 'b'
%           BP(3).A = 1
%           BP(3).B = 'c'
%           ....
%           BP(12).A = 4
%           BP(12).B = 'c' 

这适用于任意P(具有任意数字和字段名称的结构)。

我对Matlab或Python解决方案感兴趣。这个例子是用Matlab编写的。

2 个答案:

答案 0 :(得分:1)

您正在寻找两个列表中的笛卡尔积。要使用python计算它,您可以使用itertools.product

a = range(4)
b = ['a', 'b', 'c']
p = itertools.product(a,b)

then p contains:
[(0, 'a'),
 (0, 'b'),
 (0, 'c'),
 (1, 'a'),
 (1, 'b'),
 (1, 'c'),
 (2, 'a'),
 (2, 'b'),
 (2, 'c'),
 (3, 'a'),
 (3, 'b'),
 (3, 'c')]

答案 1 :(得分:0)

感谢@Johannes提及笛卡儿产品,这是Matlab解决方案:

function BP = createBP(P)
%CREATEBATCHOBJECT - get the structure and create batch BP structure Array
% Example of P:
%   P.A = 1:4;
%   P.B = {'a','b','c'};
% So the output BatchParam (BP) will be like this:
%       4*3 = 12 different combination so
%           BP(1).A = 1
%           BP(1).B = 'a'
%           BP(2).a = 1
%           BP(2).B = 'b'
%           BP(3).A = 1
%           BP(3).B = 'c'
%           ....
%           BP(12).A = 4
%           BP(12).B = 'c'
% the output parameter BP (BatchParam) will be used by runBatch function to run given
% function on the BatchParam. 
% 
% This function uses allcomb which calculate the cartesiean product of elements. It
% make sure the input of allcomb be proper cell input and also create desired BP
% structure array from the product. 

%% Parse P to proper cell for allcomb
fieldNames = fieldnames(P);
C = cell(numel(fieldNames),1);  % C contains all field of P in a cell
for i = 1:numel(fieldNames)
    C{i} = createCellFromData(P.(fieldNames{i}));
end

cartProduct = allcomb(C{:});

%% Convert Cartesian Product of the list to Arrays of Structure, BP:

% initialize the structure array (not necessary) // pre-allocate:
for i = 1:numel(fieldNames)
    BP.(fieldNames{i}) = [];
end
BP = repmat(BP,1,size(cartProduct,1));

for i = 1:size(cartProduct,1)   % for each product aka combination
    for ii = 1:numel(fieldNames)    % for each field
        BP(i).(fieldNames{ii}) = cartProduct{i,ii};
    end
end


end





%% Local Functions:
function C = createCellFromData(L)
% this function gets a input, L, which is a list, vector, character, etc and put each
% entry in a cell of a Cell: C.
switch class(L)
    case 'double'
        C = cell(1,numel(L));
        for i = 1:numel(L)
            C{i} = L(i);
        end
    case 'char'
        C{1} = L;
    case 'cell'
        C = L;
    otherwise
        error('This class has not been implemented yet');
end
end







function A = allcomb(varargin)

% ALLCOMB - All combinations
%    B = ALLCOMB(A1,A2,A3,...,AN) returns all combinations of the elements
%    in the arrays A1, A2, ..., and AN. B is P-by-N matrix is which P is the product
%    of the number of elements of the N inputs. This functionality is also
%    known as the Cartesian Product. The arguments can be numerical and/or
%    characters, or they can be cell arrays.
%
%    Examples:
%       allcomb([1 3 5],[-3 8],[0 1]) % numerical input:
%       % -> [ 1  -3   0
%       %      1  -3   1
%       %      1   8   0
%       %        ...
%       %      5  -3   1
%       %      5   8   1 ] ; % a 12-by-3 array
%
%       allcomb('abc','XY') % character arrays
%       % -> [ aX ; aY ; bX ; bY ; cX ; cY] % a 6-by-2 character array
%
%       allcomb('xy',[65 66]) % a combination
%       % -> ['xA' ; 'xB' ; 'yA' ; 'yB'] % a 4-by-2 character array
%
%       allcomb({'hello','Bye'},{'Joe', 10:12},{99999 []}) % all cell arrays
%       % -> {  'hello'  'Joe'        [99999]
%       %       'hello'  'Joe'             []
%       %       'hello'  [1x3 double] [99999]
%       %       'hello'  [1x3 double]      []
%       %       'Bye'    'Joe'        [99999]
%       %       'Bye'    'Joe'             []
%       %       'Bye'    [1x3 double] [99999]
%       %       'Bye'    [1x3 double]      [] } ; % a 8-by-3 cell array
%
%    ALLCOMB(..., 'matlab') causes the first column to change fastest which
%    is consistent with matlab indexing. Example: 
%      allcomb(1:2,3:4,5:6,'matlab') 
%      % -> [ 1 3 5 ; 1 4 5 ; 1 3 6 ; ... ; 2 4 6 ]
%
%    If one of the arguments is empty, ALLCOMB returns a 0-by-N empty array.
%    
%    See also NCHOOSEK, PERMS, NDGRID
%         and NCHOOSE, COMBN, KTHCOMBN (Matlab Central FEX)

% Tested in Matlab R2015a
% version 4.1 (feb 2016)
% (c) Jos van der Geest
% email: samelinoa@gmail.com

% History
% 1.1 (feb 2006), removed minor bug when entering empty cell arrays;
%     added option to let the first input run fastest (suggestion by JD)
% 1.2 (jan 2010), using ii as an index on the left-hand for the multiple
%     output by NDGRID. Thanks to Jan Simon, for showing this little trick
% 2.0 (dec 2010). Bruno Luong convinced me that an empty input should
% return an empty output.
% 2.1 (feb 2011). A cell as input argument caused the check on the last
%      argument (specifying the order) to crash.
% 2.2 (jan 2012). removed a superfluous line of code (ischar(..))
% 3.0 (may 2012) removed check for doubles so character arrays are accepted
% 4.0 (feb 2014) added support for cell arrays
% 4.1 (feb 2016) fixed error for cell array input with last argument being
%     'matlab'. Thanks to Richard for pointing this out.

narginchk(1,Inf) ;

NC = nargin ;

% check if we should flip the order
if ischar(varargin{end}) && (strcmpi(varargin{end},'matlab') || strcmpi(varargin{end},'john'))
    % based on a suggestion by JD on the FEX
    NC = NC-1 ;
    ii = 1:NC ; % now first argument will change fastest
else
    % default: enter arguments backwards, so last one (AN) is changing fastest
    ii = NC:-1:1 ;
end

args = varargin(1:NC) ;
% check for empty inputs
if any(cellfun('isempty',args))
    warning('ALLCOMB:EmptyInput','One of more empty inputs result in an empty output.') ;
    A = zeros(0,NC) ;
elseif NC > 1
    isCellInput = cellfun(@iscell,args) ;
    if any(isCellInput)
        if ~all(isCellInput)
            error('ALLCOMB:InvalidCellInput', ...
                'For cell input, all arguments should be cell arrays.') ;
        end
        % for cell input, we use to indices to get all combinations
        ix = cellfun(@(c) 1:numel(c), args,'un',0) ;

        % flip using ii if last column is changing fastest
        [ix{ii}] = ndgrid(ix{ii}) ;

        A = cell(numel(ix{1}),NC) ; % pre-allocate the output
        for k=1:NC
            % combine
            A(:,k) = reshape(args{k}(ix{k}),[],1) ;
        end
    else
        % non-cell input, assuming all numerical values or strings
        % flip using ii if last column is changing fastest
        [A{ii}] = ndgrid(args{ii}) ;
        % concatenate
        A = reshape(cat(NC+1,A{:}),[],NC) ;
    end
elseif NC==1
    A = args{1}(:) ; % nothing to combine

else % NC==0, there was only the 'matlab' flag argument
    A = zeros(0,0) ; % nothing
end

%% license.txt
% Copyright (c) 2016, Jos (10584)
% All rights reserved.
% 
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:
% 
%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
% 
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.


end