Как динамически создавать вложенные циклы в зависимости от количества входных аргументов - PullRequest
0 голосов
/ 14 мая 2018

Я пытаюсь построить таблицу данных, используя функцию, в которой каждая серия берется как набор чисел определенного критерия, следующим образом:

function plotter_fun(Table)

    aList = unique(Table.a);
    bList = unique(Table.b);
    cList = unique(Table.c);

    for a = aList
        for b = bList
            for c = cList
                Slice = Table(Table.a==a & Table.b==b & Table.c==c, :);
                plot(Slice.x, Slice.y);
            end
        end
    end
end

Я хочу сделать это так, чтобы параметры заголовка таблицы ('a', 'b', 'c') могли быть переданы в качестве аргумента и могли быть любым количеством параметров. Желаемый результат будет примерно таким:

function plotter_fun(Table, headerNames)

    for i = 1:numel(headerNames)
        loopList{i} = unique(Table.(headerNames{i}));
    end

    % do nested looping

end

Где это называется как:

plotter_fun(Table, {'a', 'b', 'c'});

Я не уверен, как использовать алгоритм рекурсивного цикла, чтобы число вложенных циклов можно было динамически изменять?

1 Ответ

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

Похоже, что каждый фрагмент представляет собой уникальную комбинацию значений переменных вашего заголовка.Имея это в виду, мы можем использовать findgroups и unique для полного устранения петель.Тогда ситуация с «динамическим вложением» не является проблемой ...

Эта функция работает так, как вы ее описываете:

function plotter_fun(Table, headerNames)
    % Create a matrix of group indices for each specified header
    grps = zeros(size(Table,1), numel(headerNames));
    for i = 1:numel(headerNames)
        grps(:,i) = findgroups(Table.(headerNames{i}));
    end
    % Get the unique rows for the grouping variables
    [~, ~, idx] = unique(grps, 'rows');
    % Loop over each unique row index and slice out the specified rows.
    for i = 1:max(idx)
        Slice = Table( idx == i, : );
        plot( Slice.x, Slice.y );
    end
end

Test (работает, когда строка plotудаляется, так как я не указал x или y столбцы):

tbl = cell2table( {'a', 1, 'dog'; 
                   'a', 2, 'cat'; 
                   'b', 3, 'cat'; 
                   'a', 2, 'cat'}, ...
                 'variablenames', {'char','num','pet'} )

plotter_fun( tbl, {'char', 'num', 'pet'} ) % output slices are rows [1], [2,4] and [3].

plotter_fun( tbl, {'char'} ) % output slices are rows [1,2,4] and [3].

Редактировать:

Вот гибкий способ автоматического создания "Фильтр "Метка от Slice.Мы можем объединить = между headerNames и табличными значениями (преобразованными с использованием num2str в случае наличия числовых значений), а затем использовать strjoin, чтобы сгенерировать нашу метку, разделенную , для каждого заголовка.

Один вкладыш выглядит следующим образом и будет использоваться в цикле, где определено Slice:

label = strjoin( strcat( headerNames', '=', ...
                   cellfun(@num2str,table2cell(Slice(1,headerNames)),'uni',0)' ), ', ');

% Output for Slice 1 of example 1 above: 'char=a, num=1, pet=dog'
% Output for Slice 1 of example 2 above: 'char=a'

% cellfun(@num2str, __ ) conversion not needed if there is no numeric data in the table
...